Merge "board-8064-gpio: Update FUNC for EPM SPI CS" into msm-3.0
diff --git a/Documentation/devicetree/bindings/prng/msm-rng.txt b/Documentation/devicetree/bindings/prng/msm-rng.txt
new file mode 100644
index 0000000..3d55808
--- /dev/null
+++ b/Documentation/devicetree/bindings/prng/msm-rng.txt
@@ -0,0 +1,12 @@
+* RNG (Random Number Generator)
+
+Required properties:
+- compatible : Should be "qcom,msm-rng"
+- reg        : Offset and length of the register set for the device
+
+Example:
+
+        qcom,msm-rng@f9bff000 {
+                              compatible = "qcom,msm-rng";
+                              reg = <0xf9bff000 0x200>;
+        };
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
new file mode 100644
index 0000000..cd7bdce
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -0,0 +1,21 @@
+Qualcomm Global Distributed Switch Controller (GDSC) Regulator Driver
+
+The GDSC driver, implemented under the regulator framework, is responsible for
+safely collapsing and restoring power to peripheral cores on chipsets like
+msm-copper for power savings.
+
+Required properties:
+ - compatible:      Must be "qcom,gdsc"
+ - regulator-name:  A string used as a descriptive name for regulator outputs
+ - reg:             The address of the GDSCR register
+
+Optional properties:
+ - parent-supply:   phandle to the parent supply/regulator node
+
+Example:
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_gx";
+		parent-supply = <&pm8841_s4>;
+		reg = <0xfd8c4024 0x4>;
+	};
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
new file mode 100644
index 0000000..f83fe76
--- /dev/null
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	gdsc_venus: qcom,gdsc@fd8c1024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus";
+		reg = <0xfd8c1024 0x4>;
+	};
+
+	gdsc_mdss: qcom,gdsc@fd8c2304 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_mdss";
+		reg = <0xfd8c2304 0x4>;
+	};
+
+	gdsc_jpeg: qcom,gdsc@fd8c35a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_jpeg";
+		reg = <0xfd8c35a4 0x4>;
+	};
+
+	gdsc_vfe: qcom,gdsc@fd8c36a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vfe";
+		reg = <0xfd8c36a4 0x4>;
+	};
+
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_gx";
+		reg = <0xfd8c4024 0x4>;
+	};
+
+	gdsc_oxili_cx: qcom,gdsc@fd8c4034 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_cx";
+		reg = <0xfd8c4034 0x4>;
+	};
+
+	gdsc_usb_hsic: qcom,gdsc@fc400404 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_usb_hsic";
+		reg = <0xfc400404 0x4>;
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index e807680..60f59d3 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -18,6 +18,7 @@
 /include/ "msmcopper-regulator.dtsi"
 /include/ "msmcopper-gpio.dtsi"
 /include/ "msmcopper-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
 
 / {
 	model = "Qualcomm MSM Copper";
@@ -132,6 +133,7 @@
 		qcom,bam-dma-res-pipes = <6>;
 	};
 
+
 	spi@f9924000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9924000 0x1000>;
@@ -275,6 +277,10 @@
 		qcom,dwc-usb3-msm-dbm-eps = <4>;
 	};
 
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		parent-supply = <&pm8841_s4>;
+	};
+
 	qcom,lpass@fe200000 {
 		compatible = "qcom,pil-q6v5-lpass";
 		reg = <0xfe200000 0x00100>,
@@ -302,4 +308,9 @@
 		rpm-channel-name = "rpm_requests";
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
 	};
+
+        qcom,msm-rng@f9bff000 {
+               compatible = "qcom,msm-rng";
+               reg = <0xf9bff000 0x200>;
+        };
 };
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f524828..14ba936 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -446,6 +446,8 @@
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 1c2876d..24b1c7d 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -455,6 +455,8 @@
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 289b28c..a24498c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -994,7 +994,6 @@
 	config DEBUG_MSM8960_UART
 		bool "Kernel low-level debugging messages via MSM 8960 UART"
 		depends on ARCH_MSM8960 && DEBUG_LL
-		select DEBUG_MSM8930_UART
 		select MSM_HAS_DEBUG_UART_HS
 		help
 		  Say Y here if you want the debug print routines to direct
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index dba3367..3659055 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -285,6 +285,7 @@
 obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o board-copper-gpiomux.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o clock-pll.o clock-copper.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += gdsc.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 6986a29..f467aba 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -513,15 +513,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1100000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -540,15 +540,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1050000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1075000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1125000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1150000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1200000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1175000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1200000 },
 	{ 0, { 0 } }
 };
 
@@ -567,15 +567,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1000000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1075000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1075000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1100000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1100000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1125000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1125000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1137500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1075000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1100000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1125000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1150000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 835b8b9..0234de6 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -91,6 +91,7 @@
 #endif
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE		0x20000
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE		0x3800000
@@ -103,7 +104,7 @@
 #define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
 #define MSM_ION_HEAP_NUM	8
 #endif
-#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE	(0x200000 - HOLE_SIZE) /* (2MB - 128KB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 #else
@@ -111,10 +112,11 @@
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#define APQ8064_FIXED_AREA_START 0xa0000000
+#define APQ8064_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+							HOLE_SIZE))
 #define MAX_FIXED_AREA_SIZE	0x10000000
-#define MSM_MM_FW_SIZE		0x200000
-#define APQ8064_FW_START	(APQ8064_FIXED_AREA_START - MSM_MM_FW_SIZE)
+#define MSM_MM_FW_SIZE		(0x200000 - HOLE_SIZE)
+#define APQ8064_FW_START	APQ8064_FIXED_AREA_START
 
 /* PCIe power enable pmic gpio */
 #define PCIE_PWR_EN_PMIC_GPIO 13
@@ -505,19 +507,20 @@
 		return;
 
 	if (apq8064_fmem_pdata.size) {
-		apq8064_fmem_pdata.reserved_size_low = fixed_low_size;
+		apq8064_fmem_pdata.reserved_size_low = fixed_low_size +
+								HOLE_SIZE;
 		apq8064_fmem_pdata.reserved_size_high = fixed_high_size;
 	}
 
 	/* Since the fixed area may be carved out of lowmem,
 	 * make sure the length is a multiple of 1M.
 	 */
-	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+	fixed_size = (fixed_size + HOLE_SIZE + SECTION_SIZE - 1)
 		& SECTION_MASK;
 	apq8064_reserve_fixed_area(fixed_size);
 
 	fixed_low_start = APQ8064_FIXED_AREA_START;
-	fixed_middle_start = fixed_low_start + fixed_low_size;
+	fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
 	fixed_high_start = fixed_middle_start + fixed_middle_size;
 
 	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
@@ -525,11 +528,13 @@
 
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
+			struct ion_cp_heap_pdata *pdata;
 
 			switch (heap->type) {
 			case ION_HEAP_TYPE_CP:
-				fixed_position = ((struct ion_cp_heap_pdata *)
-					heap->extra_data)->fixed_position;
+				pdata =
+				(struct ion_cp_heap_pdata *)heap->extra_data;
+				fixed_position = pdata->fixed_position;
 				break;
 			case ION_HEAP_TYPE_CARVEOUT:
 				fixed_position = ((struct ion_co_heap_pdata *)
@@ -545,6 +550,9 @@
 				break;
 			case FIXED_MIDDLE:
 				heap->base = fixed_middle_start;
+				pdata->secure_base = fixed_middle_start
+								- HOLE_SIZE;
+				pdata->secure_size = HOLE_SIZE + heap->size;
 				break;
 			case FIXED_HIGH:
 				heap->base = fixed_high_start;
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 90cfee4..62bab86 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -408,23 +408,6 @@
 	.resource	= copper_tzlog_resources,
 };
 
-#ifdef CONFIG_HW_RANDOM_MSM
-/* PRNG device */
-#define MSM_PRNG_PHYS  0xF9BFF000
-static struct resource rng_resources = {
-	.flags = IORESOURCE_MEM,
-	.start = MSM_PRNG_PHYS,
-	.end   = MSM_PRNG_PHYS + SZ_512 - 1,
-};
-
-struct platform_device msm8974_device_rng = {
-	.name          = "msm_rng",
-	.id            = 0,
-	.num_resources = 1,
-	.resource      = &rng_resources,
-};
-#endif
-
 
 void __init msm_copper_add_devices(void)
 {
@@ -436,9 +419,6 @@
 	platform_add_devices(msm_copper_stub_regulator_devices,
 					msm_copper_stub_regulator_devices_len);
 	platform_device_register(&copper_device_tz_log);
-#ifdef CONFIG_HW_RANDOM_MSM
-	platform_device_register(&msm8974_device_rng);
-#endif
 }
 
 /*
@@ -517,6 +497,8 @@
 			"pil-q6v5-lpass", NULL),
 	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
 			"pil_pronto", NULL),
+	OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
+			"msm_rng", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index fcd6386..cc48fe7 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -221,9 +221,15 @@
 	pcom_xo_enable(PCOM_XO_TCXO, PCOM_XO_DISABLE);
 }
 
+static enum handoff xo_clk_handoff(struct clk *clk)
+{
+	return HANDOFF_ENABLED_CLK;
+}
+
 static struct clk_ops clk_ops_tcxo = {
 	.enable = tcxo_clk_enable,
 	.disable = tcxo_clk_disable,
+	.handoff = xo_clk_handoff,
 	.is_local = pcom_is_local,
 };
 
@@ -250,6 +256,7 @@
 static struct clk_ops clk_ops_lpxo = {
 	.enable = lpxo_clk_enable,
 	.disable = lpxo_clk_disable,
+	.handoff = xo_clk_handoff,
 	.is_local = pcom_is_local,
 };
 
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index d0054b5..4d5f773 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -598,9 +598,16 @@
 	return;
 }
 
+static enum handoff cxo_clk_handoff(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return HANDOFF_ENABLED_CLK;
+}
+
 static struct clk_ops clk_ops_cxo = {
 	.enable = cxo_clk_enable,
 	.disable = cxo_clk_disable,
+	.handoff = cxo_clk_handoff,
 };
 
 static struct fixed_clk cxo_clk_src = {
@@ -4918,7 +4925,7 @@
 	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
 	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng.0"),
+	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
 
 	/* TODO: Remove dummy clocks as soon as they become unnecessary */
 	CLK_DUMMY("phy_clk",       NULL,    "msm_otg", OFF),
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 08211a2..f8ab18a 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -400,6 +400,4 @@
 
 extern struct platform_device copper_device_tz_log;
 
-extern struct platform_device msm8974_device_rng;
-
 extern struct platform_device mdm_sglte_device;
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
new file mode 100644
index 0000000..a77ac24
--- /dev/null
+++ b/arch/arm/mach-msm/gdsc.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define PWR_ON_MASK		BIT(31)
+#define EN_REST_WAIT_MASK	(0xF << 20)
+#define EN_FEW_WAIT_MASK	(0xF << 16)
+#define CLK_DIS_WAIT_MASK	(0xF << 12)
+#define SW_OVERRIDE_MASK	BIT(2)
+#define HW_CONTROL_MASK		BIT(1)
+#define SW_COLLAPSE_MASK	BIT(0)
+
+/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
+#define EN_REST_WAIT_VAL	(0x2 << 20)
+#define EN_FEW_WAIT_VAL		(0x2 << 16)
+#define CLK_DIS_WAIT_VAL	(0x2 << 12)
+
+#define TIMEOUT_US		10
+
+struct gdsc {
+	struct regulator_dev	*rdev;
+	struct regulator_desc	rdesc;
+	void __iomem		*gdscr;
+};
+
+static int gdsc_is_enabled(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+
+	return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
+}
+
+static int gdsc_enable(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+	uint32_t regval;
+	int ret;
+
+	regval = readl_relaxed(sc->gdscr);
+	regval &= ~SW_COLLAPSE_MASK;
+	writel_relaxed(regval, sc->gdscr);
+
+	ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
+				       TIMEOUT_US);
+	if (ret)
+		dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
+
+	return ret;
+}
+
+static int gdsc_disable(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+	uint32_t regval;
+	int ret;
+
+	regval = readl_relaxed(sc->gdscr);
+	regval |= SW_COLLAPSE_MASK;
+	writel_relaxed(regval, sc->gdscr);
+
+	ret = readl_tight_poll_timeout(sc->gdscr, regval,
+				       !(regval & PWR_ON_MASK), TIMEOUT_US);
+	if (ret)
+		dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+
+	return ret;
+}
+
+static struct regulator_ops gdsc_ops = {
+	.is_enabled = gdsc_is_enabled,
+	.enable = gdsc_enable,
+	.disable = gdsc_disable,
+};
+
+static int __devinit gdsc_probe(struct platform_device *pdev)
+{
+	static atomic_t gdsc_count = ATOMIC_INIT(-1);
+	struct regulator_init_data *init_data;
+	struct resource *res;
+	struct gdsc *sc;
+	uint32_t regval;
+	int ret;
+
+	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
+	if (sc == NULL)
+		return -ENOMEM;
+
+	init_data = of_get_regulator_init_data(&pdev->dev);
+	if (init_data == NULL)
+		return -ENOMEM;
+
+	if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
+	ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
+				      &sc->rdesc.name);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -EINVAL;
+	sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (sc->gdscr == NULL)
+		return -ENOMEM;
+
+	sc->rdesc.id = atomic_inc_return(&gdsc_count);
+	sc->rdesc.ops = &gdsc_ops;
+	sc->rdesc.type = REGULATOR_VOLTAGE;
+	sc->rdesc.owner = THIS_MODULE;
+	platform_set_drvdata(pdev, sc);
+
+	/*
+	 * Disable HW trigger: collapse/restore occur based on registers writes.
+	 * Disable SW override: Use hardware state-machine for sequencing.
+	 */
+	regval = readl_relaxed(sc->gdscr);
+	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
+
+	/* Configure wait time between states. */
+	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
+	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+	writel_relaxed(regval, sc->gdscr);
+
+	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
+				      pdev->dev.of_node);
+	if (IS_ERR(sc->rdev)) {
+		dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
+			sc->rdesc.name);
+		return PTR_ERR(sc->rdev);
+	}
+
+	return 0;
+}
+
+static int __devexit gdsc_remove(struct platform_device *pdev)
+{
+	struct gdsc *sc = platform_get_drvdata(pdev);
+	regulator_unregister(sc->rdev);
+	return 0;
+}
+
+static struct of_device_id gdsc_match_table[] = {
+	{ .compatible = "qcom,gdsc" },
+	{}
+};
+
+static struct platform_driver gdsc_driver = {
+	.probe		= gdsc_probe,
+	.remove		= __devexit_p(gdsc_remove),
+	.driver		= {
+		.name		= "gdsc",
+		.of_match_table = gdsc_match_table,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init gdsc_init(void)
+{
+	return platform_driver_register(&gdsc_driver);
+}
+subsys_initcall(gdsc_init);
+
+static void __exit gdsc_exit(void)
+{
+	platform_driver_unregister(&gdsc_driver);
+}
+module_exit(gdsc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Copper GDSC power rail regulator driver");
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index 3c475d6..126f8e0 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -23,6 +23,7 @@
 #include <linux/fs.h>
 
 #include <mach/irqs.h>
+#include <mach/msm_smsm.h>
 #include <mach/scm.h>
 #include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
@@ -42,6 +43,32 @@
 
 static int crash_shutdown;
 
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_gss_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("GSS subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
 static void gss_fatal_fn(struct work_struct *work)
 {
 	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
@@ -58,6 +85,7 @@
 		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
 			"Probable err_fatal on the GSS. "
 			"Calling subsystem restart...\n");
+		log_gss_sfr();
 		subsystem_restart("gss");
 
 	} else if (gss_state & reset_smsm_states) {
@@ -68,6 +96,7 @@
 		kernel_restart(NULL);
 	} else {
 		/* TODO: Bus unlock code/sequence goes _here_ */
+		log_gss_sfr();
 		subsystem_restart("gss");
 	}
 }
@@ -84,6 +113,7 @@
 		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
 			"Probable err_fatal on the GSS. "
 			"Calling subsystem restart...\n");
+		log_gss_sfr();
 		subsystem_restart("gss");
 	}
 }
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 58bf45d..aaa2086 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -132,4 +132,6 @@
 
 source "drivers/clocksource/Kconfig"
 
+source "drivers/gud/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 82008ed..13dc06e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -126,3 +126,6 @@
 obj-y				+= clk/
 
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
+
+#MobiCore
+obj-$(CONFIG_MOBICORE_SUPPORT)  += gud/
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index 974b77e..7e6670d 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -231,12 +231,19 @@
 	return 0;
 }
 
+static struct of_device_id qrng_match[] = {
+	{	.compatible = "qcom,msm-rng",
+	},
+	{}
+};
+
 static struct platform_driver rng_driver = {
 	.probe      = msm_rng_probe,
 	.remove     = __devexit_p(msm_rng_remove),
 	.driver     = {
 		.name   = DRIVER_NAME,
 		.owner  = THIS_MODULE,
+		.of_match_table = qrng_match,
 	}
 };
 
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index c239910..83afb25 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -136,9 +136,11 @@
 				}
 
 				cp_data->virt_addr = fmem_info->virt;
-				cp_data->secure_base = heap->base;
-				cp_data->secure_size =
+				if (!cp_data->secure_base) {
+					cp_data->secure_base = heap->base;
+					cp_data->secure_size =
 						heap->size + shared_heap->size;
+				}
 			} else if (!heap->base) {
 				ion_set_base_address(heap, shared_heap,
 					co_heap_data, cp_data);
diff --git a/drivers/gud/Kconfig b/drivers/gud/Kconfig
new file mode 100644
index 0000000..3a241b7
--- /dev/null
+++ b/drivers/gud/Kconfig
@@ -0,0 +1,32 @@
+#
+# MobiCore configuration
+#
+config MOBICORE_SUPPORT
+	tristate "Linux MobiCore Support"
+	#depends on ARM_TRUSTZONE
+	---help---
+	  Enable Linux Kernel MobiCore Support
+
+config MOBICORE_DEBUG
+    bool "MobiCore Module debug mode"
+    depends on MOBICORE_SUPPORT
+    ---help---
+      Enable Debug mode in the MobiCore Driver.
+      It enables printing information about mobicore operations
+
+config MOBICORE_VERBOSE
+    bool "MobiCore Module verbose debug mode"
+    depends on MOBICORE_DEBUG
+    ---help---
+      Enable Verbose Debug mode in the MobiCore Driver.
+      It enables printing extra information about mobicore operations
+      Beware: this is only useful for debuging deep in the driver because
+      it prints too much logs
+
+
+config MOBICORE_API
+    tristate "Linux MobiCore API"
+    depends on MOBICORE_SUPPORT
+    ---help---
+      Enable Linux Kernel MobiCore API
+
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
new file mode 100644
index 0000000..ea212c5
--- /dev/null
+++ b/drivers/gud/Makefile
@@ -0,0 +1,31 @@
+#
+# Makefile for the kernel mobicore drivers
+#
+GUD_ROOT_FOLDER := drivers/gud
+# add our modules to kernel.
+obj-$(CONFIG_MOBICORE_API) += mckernelapi.o
+obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o
+
+mcdrvmodule-objs := mobicore_driver/logging.o mobicore_driver/main.o
+
+mckernelapi-objs := mobicore_kernelapi/main.o \
+		mobicore_kernelapi/clientlib.o \
+		mobicore_kernelapi/device.o \
+		mobicore_kernelapi/session.o \
+		mobicore_kernelapi/connection.o
+
+# Release mode by default
+ccflags-y := -DNDEBUG
+ccflags-y += -Wno-declaration-after-statement
+
+ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
+ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE
+
+# Choose one platform from the folder
+MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/platforms | tail -1) )
+# Use the available platform folder
+ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/platforms/$(MOBICORE_PLATFORM)
+
+
+ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/public
+ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_kernelapi/include
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
new file mode 100644
index 0000000..43541bb
--- /dev/null
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -0,0 +1,29 @@
+/**
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2012-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define MOBICORE_COMPONENT_BUILD_TAG "*** GC_MSM8960_Release_V010 ###"
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c
new file mode 100644
index 0000000..eb44c8a
--- /dev/null
+++ b/drivers/gud/mobicore_driver/logging.c
@@ -0,0 +1,336 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_LOGGING MobiCore Driver Logging Subsystem.
+ * @ingroup  MCD_MCDIMPL_KMOD
+ * @{
+ * @file
+ * MobiCore Driver Logging Subsystem.
+ * The logging subsytem provides the interface between the Mobicore trace
+ * buffer and the Linux log
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include "mc_drv_module.h"
+#include "mc_drv_module_linux_api.h"
+#include "mc_drv_module_fastcalls.h"
+
+/* Default len of the log ring buffer 256KB*/
+#define LOG_BUF_SIZE	(64 * PAGE_SIZE)
+
+/* Max Len of a log line for printing */
+#define LOG_LINE_SIZE	256
+
+static uint32_t log_size = LOG_BUF_SIZE;
+module_param(log_size, uint, 0);
+MODULE_PARM_DESC(log_size, " Size of the MobiCore log ringbuffer "
+						"(or 256KB default).");
+
+/*----------------------------------------------------------------------------*/
+/* Definitions for log version 2 */
+#define LOG_TYPE_MASK				(0x0007)
+#define LOG_TYPE_CHAR				0
+#define LOG_TYPE_INTEGER			1
+/* Field length */
+#define LOG_LENGTH_MASK				(0x00F8)
+#define LOG_LENGTH_SHIFT			3
+/* Extra attributes */
+#define LOG_EOL					(0x0100)
+#define LOG_INTEGER_DECIMAL			(0x0200)
+#define LOG_INTEGER_SIGNED			(0x0400)
+
+struct logmsg_struct {
+	/* Type and format of data */
+	uint16_t ctrl;
+	/* Unique value for each event source */
+	uint16_t source;
+	/* Value, if any */
+	uint32_t log_data;
+};
+
+/** MobiCore log previous position */
+static uint32_t log_pos;
+/** MobiCore log buffer structure */
+static struct mc_trace_buf *log_buf;
+/** Log Thread task structure */
+struct task_struct *log_thread;
+/** Log Line buffer */
+static char *log_line;
+
+static void log_msg(struct logmsg_struct *msg);
+
+/*----------------------------------------------------------------------------*/
+static void log_eol(void)
+{
+	if (!strnlen(log_line, LOG_LINE_SIZE))
+		return;
+	printk(KERN_INFO "%s\n", log_line);
+	log_line[0] = 0;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Put a char to the log line if there is enough space if not then also
+ * output the line. Assume nobody else is updating the line! */
+static void log_char(char ch)
+{
+	uint32_t len;
+	if (ch == '\n' || ch == '\r') {
+		log_eol();
+		return;
+	}
+
+	if (strnlen(log_line, LOG_LINE_SIZE) >= LOG_LINE_SIZE - 1) {
+		printk(KERN_INFO "%s\n", log_line);
+		log_line[0] = 0;
+	}
+
+	len = strnlen(log_line, LOG_LINE_SIZE);
+	log_line[len] = ch;
+	log_line[len + 1] = 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Put a string to the log line if there is enough space if not then also
+ * output the line. Assume nobody else is updating the line! */
+static void log_str(const char *s)
+{
+	int i;
+	for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++)
+		log_char(s[i]);
+}
+
+/*----------------------------------------------------------------------------*/
+static uint32_t process_v1log(void)
+{
+	char *last_char = log_buf->buff + log_buf->write_pos;
+	char *buff = log_buf->buff + log_pos;
+	while (buff != last_char) {
+		log_char(*(buff++));
+		/* Wrap around */
+		if (buff - (char *)log_buf >= log_size)
+			buff = log_buf->buff;
+	}
+	return buff - log_buf->buff;
+}
+
+/*----------------------------------------------------------------------------*/
+static uint32_t process_v2log(void)
+{
+	char *last_msg = log_buf->buff + log_buf->write_pos;
+	char *buff = log_buf->buff + log_pos;
+	while (buff != last_msg) {
+		log_msg((struct logmsg_struct *)buff);
+		buff += sizeof(struct logmsg_struct);
+		/* Wrap around */
+		if (buff + sizeof(struct logmsg_struct) >
+			(char *)log_buf + log_size)
+			buff = log_buf->buff;
+	}
+	return buff - log_buf->buff;
+}
+
+static const uint8_t HEX2ASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+				'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+/*----------------------------------------------------------------------------*/
+static void dbg_raw_nro(uint32_t format, uint32_t value)
+{
+	int digits = 1;
+	uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16;
+	int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT;
+	int negative = FALSE;
+	uint32_t digit_base = 1;
+
+	if ((format & LOG_INTEGER_SIGNED) != 0 && ((signed int)value) < 0) {
+			negative = TRUE;
+			value = (uint32_t)(-(signed int)value);
+			width--;
+	}
+
+	/* Find length and divider to get largest digit */
+	while (value / digit_base >= base) {
+			digit_base *= base;
+			digits++;
+	}
+
+	if (width > digits) {
+		char ch = (base == 10) ? ' ' : '0';
+		while (width > digits) {
+			log_char(ch);
+			width--;
+		}
+	}
+
+	if (negative)
+		log_char('-');
+
+	while (digits-- > 0) {
+		uint32_t d = value / digit_base;
+		log_char(HEX2ASCII[d]);
+		value = value - d * digit_base;
+		digit_base /= base;
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+static void log_msg(struct logmsg_struct *msg)
+{
+	unsigned char msgtxt[5];
+	int mpos = 0;
+	switch (msg->ctrl & LOG_TYPE_MASK) {
+	case LOG_TYPE_CHAR: {
+		uint32_t ch;
+		ch = msg->log_data;
+		while (ch != 0) {
+			msgtxt[mpos++] = ch&0xFF;
+			ch >>= 8;
+		}
+		msgtxt[mpos] = 0;
+		log_str(msgtxt);
+		break;
+	}
+	case LOG_TYPE_INTEGER: {
+		dbg_raw_nro(msg->ctrl, msg->log_data);
+		break;
+	}
+	default:
+		break;
+	}
+	if (msg->ctrl & LOG_EOL)
+		log_eol();
+}
+
+/*----------------------------------------------------------------------------*/
+static int log_worker(void *p)
+{
+	if (log_buf == NULL)
+		return -EFAULT;
+
+	/* The thread should have never started */
+	if (log_buf == NULL)
+		return -EFAULT;
+
+	while (!kthread_should_stop()) {
+		if (log_buf->write_pos == log_pos)
+			schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
+
+		switch (log_buf->version) {
+		case 1:
+			log_pos = process_v1log();
+			break;
+		case 2:
+			log_pos = process_v2log();
+			break;
+		default:
+			MCDRV_DBG_ERROR("Unknown Mobicore log data "
+				"version %d logging disabled.",
+				log_buf->version);
+			log_pos = log_buf->write_pos;
+			/* Stop the thread as we have no idea what
+			 * happens next */
+			return -EFAULT;
+		}
+	}
+	MCDRV_DBG("Logging thread stopped!");
+	return 0;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Wakeup the log reader thread
+ * This should be called from the places where calls into MobiCore have
+ * generated some logs(eg, yield, SIQ...)
+ */
+void mobicore_log_read(void)
+{
+	if (log_thread == NULL || IS_ERR(log_thread))
+		return;
+
+	wake_up_process(log_thread);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Setup mobicore kernel log. It assumes it's running on CORE 0!
+ * The fastcall will complain is that is not the case!
+ */
+long mobicore_log_setup(void *data)
+{
+	unsigned long phys_log_buf;
+	union fc_generic fc_log;
+
+	log_pos = 0;
+	log_buf = NULL;
+	log_thread = NULL;
+	log_line = NULL;
+
+	/* Sanity check for the log size */
+	if (log_size < PAGE_SIZE)
+		return -EFAULT;
+	else
+		log_size =
+			get_nr_of_pages_for_buffer(NULL, log_size) * PAGE_SIZE;
+
+	log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL);
+	if (IS_ERR(log_line)) {
+		MCDRV_DBG_ERROR("failed to allocate log line!");
+		return -ENOMEM;
+	}
+
+	log_thread = kthread_create(log_worker, NULL, "mobicore_log");
+	if (IS_ERR(log_thread)) {
+		MCDRV_DBG_ERROR("mobicore log thread creation failed!");
+		return -EFAULT;
+	}
+
+	log_pos = 0;
+	log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+					size_to_order(log_size));
+	if (!log_buf) {
+		MCDRV_DBG_ERROR("Failed to get page for logger!");
+		return -ENOMEM;
+	}
+	phys_log_buf = virt_to_phys(log_buf);
+
+	memset(&fc_log, 0, sizeof(fc_log));
+	fc_log.as_in.cmd      = MC_FC_NWD_TRACE;
+	fc_log.as_in.param[0] = phys_log_buf;
+	fc_log.as_in.param[1] = log_size;
+
+	MCDRV_DBG("fc_log virt=%p phys=%p ", log_buf, (void *)phys_log_buf);
+	mc_fastcall(&fc_log);
+	MCDRV_DBG("fc_log out ret=0x%08x", fc_log.as_out.ret);
+	/* If the setup failed we must free the memory allocated */
+	if (fc_log.as_out.ret) {
+		MCDRV_DBG_ERROR("MobiCore shared traces setup failed!");
+		kthread_stop(log_thread);
+		free_pages((unsigned long)log_buf, size_to_order(log_size));
+
+		log_buf = NULL;
+		log_thread = NULL;
+		return -EIO;
+	}
+
+	MCDRV_DBG("fc_log Logger version %u\n", log_buf->version);
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Free kernel log componenets.
+ * ATTN: We can't free the log buffer because it's also in use by MobiCore and
+ * even if the module is unloaded MobiCore is still running.
+ */
+void mobicore_log_free(void)
+{
+	if (log_thread && !IS_ERR(log_thread)) {
+		/* We don't really care what the thread returns for exit */
+		kthread_stop(log_thread);
+	}
+
+	kfree(log_line);
+}
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
new file mode 100644
index 0000000..9a99c5c
--- /dev/null
+++ b/drivers/gud/mobicore_driver/main.c
@@ -0,0 +1,2868 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#include "mc_drv_module.h"
+#include "mc_drv_module_linux_api.h"
+#include "mc_drv_module_android.h"
+#include "mc_drv_module_fastcalls.h"
+#include "public/mc_kernel_api.h"
+
+/* Initial value for the daemon sempahore signaling */
+#define DAEMON_SEM_VAL 0
+
+/** MobiCore interrupt context data */
+static struct mc_drv_kmod_ctx	mc_drv_kmod_ctx;
+
+/** MobiCore MCI information */
+static uint32_t mci_base;
+/*
+#############################################################################
+##
+## Convenience functions for Linux API functions
+##
+#############################################################################*/
+static int goto_cpu0(void);
+static int goto_all_cpu(void) __attribute__ ((unused));
+
+
+/*----------------------------------------------------------------------------*/
+static void init_and_add_to_list(
+	struct list_head *item,
+	struct list_head *list_head
+)
+{
+	INIT_LIST_HEAD(item);
+
+	list_add(item, list_head);
+}
+
+/*----------------------------------------------------------------------------*/
+/** check if CPU supports the ARM TrustZone Security Extensions
+ *	@return int TRUE or FALSE */
+static int has_security_extensions(
+	void
+)
+{
+	u32 fea = 0;
+	asm volatile(
+		"mrc p15, 0, %[fea], cr0, cr1, 0" :
+		[fea]"=r" (fea));
+
+	MCDRV_DBG_VERBOSE("CPU Features: 0x%X", fea);
+
+	/* If the CPU features ID has 0 for security features then the CPU
+	 * doesn't support TrustZone at all!
+	 */
+	if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0)
+		return 0;
+
+	return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/** check if running in secure mode
+ *	@return int TRUE or FALSE */
+static int is_secure_mode(
+	void
+)
+{
+	u32 cpsr = 0, nsacr = 0;
+	asm volatile(
+		"mrc	p15, 0, %[nsacr], cr1, cr1, 2\n"
+		"mrs %[cpsr], cpsr\n" :
+		[nsacr]"=r" (nsacr),
+		[cpsr]"=r"(cpsr));
+
+	MCDRV_DBG_VERBOSE("CPRS.M = set to 0x%X\n", cpsr & ARM_CPSR_MASK);
+	MCDRV_DBG_VERBOSE("SCR.NS = set to 0x%X\n", nsacr);
+
+	/* If the NSACR contains the reset value(=0) then most likely we are
+	 * running in Secure MODE.
+	 * If the cpsr mode is set to monitor mode then we cannot load!
+	 */
+	if (nsacr == 0 || ((cpsr & ARM_CPSR_MASK) == ARM_MONITOR_MODE))
+		return 1;
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/** check if userland caller is privileged (aka has "root" access rights).
+	@return int TRUE or FALSE */
+static int is_userland_caller_privileged(
+	void
+) {
+	/* For some platforms we cannot run the Daemon as root - for Android
+	 * compliance tests it is not allowed, thus we assume the daemon is ran
+	 * as the system user.
+	 * In Android the system user for daemons has no particular capabilities
+	 * other than a fixed UID: AID_SYSTEM 1000
+	 * The actual number is guaranteed to be the same in all Android systems
+	 * so we will take it for granted: see android_filesystem_config.h in
+	 * the Android source tree for all UIDs and their meaning:
+	 * http://android-dls.com/wiki/index.php?title=Android_UIDs_and_GIDs
+	 */
+#ifdef MC_ANDROID_UID_CHECK
+	return current_euid() <= AID_SYSTEM;
+#else
+	/* capable should cover all possibilities, root or sudo, uid checking
+	 * was not very reliable */
+	return capable(CAP_SYS_ADMIN);
+#endif
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+static void unlock_page_from_used_l2_table(
+	struct page *page
+){
+	/* REV axh: check if we should do this. */
+	SetPageDirty(page);
+
+	/* release page, old api was page_cache_release() */
+	ClearPageReserved(page);
+	put_page(page);
+}
+
+/*----------------------------------------------------------------------------*/
+/* convert L2 PTE to page pointer */
+static struct page *l2_pte_to_page(
+	pte_t pte
+) {
+	void *phys_page_addr	= (void *)((unsigned int)pte & PAGE_MASK);
+	unsigned int pfn	= addr_to_pfn(phys_page_addr);
+	struct page *page	= pfn_to_page(pfn);
+	return page;
+}
+
+/*----------------------------------------------------------------------------*/
+/* convert page pointer to L2 PTE */
+static pte_t page_to_l2_pte(
+	struct page *page
+)
+{
+	unsigned int pfn	= page_to_pfn(page);
+	void *phys_addr		= pfn_to_addr(pfn);
+	pte_t pte		= (pte_t)((unsigned int)phys_addr & PAGE_MASK);
+	return pte;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static inline int lock_user_pages(
+	struct task_struct	*task,
+	void			*virt_start_page_addr,
+	int			nr_of_pages,
+	struct page		**pages
+)
+{
+	int		ret = 0;
+	int		locked_pages = 0;
+	unsigned int	i;
+
+	do {
+
+		/* lock user pages, must hold the mmap_sem to do this. */
+		down_read(&(task->mm->mmap_sem));
+		locked_pages = get_user_pages(
+					  task,
+					  task->mm,
+					  (unsigned long)virt_start_page_addr,
+					  nr_of_pages,
+					  1, /* write access */
+					  0, /* they say drivers should always
+						pass 0 here..... */
+					  pages,
+					  NULL); /* we don't need the VMAs */
+		up_read(&(task->mm->mmap_sem));
+
+		/* could as lock all pages? */
+		if (locked_pages != nr_of_pages) {
+			MCDRV_DBG_ERROR(
+				"get_user_pages() failed, "
+				"locked_pages=%d\n",
+				locked_pages);
+			ret = -ENOMEM;
+			/* check if an error has been returned. */
+			if (locked_pages < 0) {
+				ret = locked_pages;
+				locked_pages = 0;
+			}
+			break;
+		}
+
+		/* do cache maintenance on locked pages. */
+		for (i = 0; i < nr_of_pages; i++)
+			flush_dcache_page(pages[i]);
+
+	} while (FALSE);
+
+
+	if (ret != 0) {
+		/* release all locked pages. */
+		MCDRV_ASSERT(locked_pages >= 0);
+		for (i = 0; i < locked_pages; i++)
+			put_page(pages[i]);
+	}
+
+	return ret;
+
+}
+
+/*
+#############################################################################
+##
+## Driver implementation functions
+##
+#############################################################################*/
+/*----------------------------------------------------------------------------*/
+/* check if caller is MobiCore Daemon */
+static unsigned int is_caller_mc_daemon(
+	struct mc_instance *instance
+)
+{
+	return ((instance != NULL)
+		&& (mc_drv_kmod_ctx.daemon_inst == instance));
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Get process context from file pointer */
+static struct mc_instance *get_instance(
+	struct file *file
+) {
+	MCDRV_ASSERT(file != NULL);
+
+	return (struct mc_instance *)(file->private_data);
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Get a unique ID */
+static unsigned int get_mc_kmod_unique_id(
+	void
+)
+{
+	return (unsigned int)atomic_inc_return(
+			   &(mc_drv_kmod_ctx.unique_counter));
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Get kernel pointer to shared L2 table given a per-process reference */
+static struct l2table *get_l2_table_kernel_virt(
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	MCDRV_ASSERT(used_l2table != NULL);
+	MCDRV_ASSERT(used_l2table->set != NULL);
+	MCDRV_ASSERT(used_l2table->set->kernel_virt != NULL);
+	return &(used_l2table->set->kernel_virt->table[used_l2table->idx]);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Get physical address of a shared L2 table given a per-process reference */
+static struct l2table *get_l2_table_phys(
+	struct mc_used_l2_table  *used_l2table
+)
+{
+	MCDRV_ASSERT(used_l2table != NULL);
+	MCDRV_ASSERT(used_l2table->set != NULL);
+	MCDRV_ASSERT(used_l2table->set->phys != NULL);
+	return &(used_l2table->set->phys->table[used_l2table->idx]);
+}
+
+/*----------------------------------------------------------------------------*/
+static unsigned int is_in_use_used_l2_table(
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	return ((used_l2table->flags &
+			  (MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP
+			   | MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC)) != 0);
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+static struct mc_used_l2_table *find_used_l2_table_by_handle(
+	unsigned int	handle
+) {
+	struct mc_used_l2_table  *used_l2table;
+	struct mc_used_l2_table  *used_l2table_with_handle = NULL;
+
+	list_for_each_entry(
+		used_l2table,
+		&(mc_drv_kmod_ctx.mc_used_l2_tables),
+		list
+	) {
+		if (handle == used_l2table->handle) {
+			used_l2table_with_handle = used_l2table;
+			break;
+		}
+	}
+
+	return used_l2table_with_handle;
+}
+
+/*
+#############################################################################
+##
+## L2 Table Pool
+##
+#############################################################################*/
+
+/*----------------------------------------------------------------------------*/
+static struct mc_used_l2_table *allocate_used_l2_table(
+	struct mc_instance	*instance
+) {
+	int				ret = 0;
+	struct mc_l2_table_store	*l2table_store = NULL;
+	struct mc_l2_tables_set		*l2table_set = NULL;
+	struct mc_used_l2_table		*used_l2table = NULL;
+	struct page			*page;
+	unsigned int			i = 0;
+
+	do {
+		/* allocate a WSM L2 descriptor */
+		used_l2table  = kmalloc(sizeof(*used_l2table), GFP_KERNEL);
+		if (used_l2table == NULL) {
+			ret = -ENOMEM;
+			MCDRV_DBG_ERROR("out of memory\n");
+			break;
+		}
+		/* clean */
+		memset(used_l2table, 0, sizeof(*used_l2table));
+		used_l2table->handle = get_mc_kmod_unique_id();
+		used_l2table->owner = instance;
+
+		/* add to global list. */
+		init_and_add_to_list(
+			&(used_l2table->list),
+			&(mc_drv_kmod_ctx.mc_used_l2_tables));
+
+		/* walk though list to find free set. */
+		list_for_each_entry(
+			l2table_set,
+			&(mc_drv_kmod_ctx.mc_l2_tables_sets),
+			list
+		) {
+			for (i = 0; i < MC_DRV_KMOD_L2_TABLE_PER_PAGES; i++) {
+				if ((l2table_set->usage_bitmap & (1U << i))
+					== 0) {
+					/* found a set,
+						l2table_set and i are set. */
+					l2table_store =
+						l2table_set->kernel_virt;
+					break;
+				}
+			}
+			if (l2table_store != NULL)
+				break;
+		} /* end while */
+
+		if (l2table_store == NULL) {
+			l2table_store = (struct mc_l2_table_store *)
+						get_zeroed_page(GFP_KERNEL);
+			if (l2table_store == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			/* Actually, locking is not necessary, because kernel
+				memory is not supposed to get swapped out. But
+				we play safe.... */
+			page = virt_to_page(l2table_store);
+			SetPageReserved(page);
+
+			/* allocate a descriptor */
+			l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL);
+			if (l2table_set == NULL) {
+				kfree(l2table_store);
+				ret = -ENOMEM;
+				break;
+			}
+			/* initialize */
+			memset(l2table_set, 0, sizeof(*l2table_set));
+
+			l2table_set->kernel_virt = l2table_store;
+			l2table_set->page = page;
+			l2table_set->phys = (void *)virt_to_phys(l2table_store);
+
+			/* init add to list. */
+			init_and_add_to_list(
+				&(l2table_set->list),
+				&(mc_drv_kmod_ctx.mc_l2_tables_sets));
+
+			/* use first table */
+			i = 0;
+		}
+
+		/* set set usage */
+		l2table_set->usage_bitmap |= (1U << i);
+
+		/* set set reference */
+		used_l2table->set = l2table_set;
+		used_l2table->idx = i;
+
+		MCDRV_DBG_VERBOSE(
+			"chunkPhys=%p,idx=%d\n",
+			l2table_set->phys, i);
+
+	} while (FALSE);
+
+	if (ret != 0) {
+		if (used_l2table != NULL) {
+			/* remove from list */
+			list_del(&(l2table_set->list));
+			/* free memory */
+			kfree(used_l2table);
+			used_l2table = NULL;
+		}
+	}
+
+	return used_l2table;
+}
+
+/*----------------------------------------------------------------------------*/
+static void free_used_l2_table(
+	struct mc_used_l2_table *used_l2table
+)
+{
+	struct mc_l2_tables_set	*l2table_set;
+	unsigned int		idx;
+
+	MCDRV_ASSERT(used_l2table != NULL);
+
+	l2table_set = used_l2table->set;
+	MCDRV_ASSERT(l2table_set != NULL);
+
+	/* clean usage flag */
+	idx = used_l2table->idx;
+	MCDRV_ASSERT(idx < MC_DRV_KMOD_L2_TABLE_PER_PAGES);
+	l2table_set->usage_bitmap &= ~(1U << idx);
+
+	/* if nobody uses this set, we can release it. */
+	if (l2table_set->usage_bitmap == 0) {
+		MCDRV_ASSERT(l2table_set->page != NULL);
+		ClearPageReserved(l2table_set->page);
+
+		MCDRV_ASSERT(l2table_set->kernel_virt != NULL);
+		free_page((unsigned long)l2table_set->kernel_virt);
+
+		/* remove from list */
+		list_del(&(l2table_set->list));
+
+		/* free memory */
+		kfree(l2table_set);
+	}
+
+	return;
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Create a L2 table in a WSM container that has been allocates previously.
+ *
+ * @param task		pointer to task owning WSM
+ * @param wsm_buffer	user space WSM start
+ * @param wsm_len	WSM length
+ * @param used_l2table	Pointer to L2 table details
+ */
+static int map_buffer_into_used_l2_table(
+	struct task_struct	*task,
+	void			*wsm_buffer,
+	unsigned int		wsm_len,
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	int		ret = 0;
+	unsigned int	i, nr_of_pages;
+	void		*virt_addr_page;
+	struct page	*page;
+	struct l2table	*l2table;
+	struct page	**l2table_as_array_of_pointers_to_page;
+
+	/* task can be null when called from kernel space */
+	MCDRV_ASSERT(wsm_buffer != NULL);
+	MCDRV_ASSERT(wsm_len != 0);
+	MCDRV_ASSERT(used_l2table != NULL);
+
+	MCDRV_DBG_VERBOSE("WSM addr=0x%p, len=0x%08x\n", wsm_buffer, wsm_len);
+
+	/* Check if called from kernel space wsm_buffer is actually
+	 * vmalloced or not */
+	if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+		MCDRV_DBG_ERROR("WSM addr is not a vmalloc address");
+		return -EINVAL;
+	}
+
+	l2table = get_l2_table_kernel_virt(used_l2table);
+	/* We use the memory for the L2 table to hold the pointer
+	and convert them later. This works, as everything comes
+	down to a 32 bit value. */
+	l2table_as_array_of_pointers_to_page = (struct page **)l2table;
+
+	do {
+
+		/* no size > 1Mib supported */
+		if (wsm_len > SZ_1M) {
+			MCDRV_DBG_ERROR("size > 1 MiB\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* calculate page usage */
+		virt_addr_page = get_page_start(wsm_buffer);
+		nr_of_pages  = get_nr_of_pages_for_buffer(wsm_buffer, wsm_len);
+
+
+		MCDRV_DBG_VERBOSE("virt addr pageStart=0x%p,pages=%d\n",
+				  virt_addr_page,
+				  nr_of_pages);
+
+		/* L2 table can hold max 1MiB in 256 pages. */
+		if ((nr_of_pages*PAGE_SIZE) > SZ_1M) {
+			MCDRV_DBG_ERROR("WSM paged exceed 1 MiB\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* Request comes from user space */
+		if (task != NULL) {
+			/* lock user page in memory, so they do not get swapped
+			* out.
+			* REV axh:
+			* Kernel 2.6.27 added a new get_user_pages_fast()
+			* function, maybe it is called fast_gup() in some
+			* versions.
+			* handle user process doing a fork().
+			* Child should not get things.
+			* http://osdir.com/ml/linux-media/2009-07/msg00813.html
+			* http://lwn.net/Articles/275808/ */
+
+			ret = lock_user_pages(
+					  task,
+					  virt_addr_page,
+					  nr_of_pages,
+					  l2table_as_array_of_pointers_to_page);
+			if (ret != 0) {
+				MCDRV_DBG_ERROR("lock_user_pages() failed\n");
+				break;
+			}
+		}
+		/* Request comes from kernel space(vmalloc buffer) */
+		else {
+			void *uaddr = wsm_buffer;
+			for (i = 0; i < nr_of_pages; i++) {
+				page = vmalloc_to_page(uaddr);
+				if (!page) {
+					MCDRV_DBG_ERROR(
+						"vmalloc_to_Page()"
+						" failed to map address\n");
+					ret = -EINVAL;
+					break;
+				}
+				get_page(page);
+				/* Lock the page in memory, it can't be swapped
+				 * out */
+				SetPageReserved(page);
+				l2table_as_array_of_pointers_to_page[i] = page;
+				uaddr += PAGE_SIZE;
+			}
+		}
+
+		used_l2table->nr_of_pages = nr_of_pages;
+		used_l2table->flags |= MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP;
+
+		/* create L2 Table entries. used_l2table->table contains a list
+		of page pointers here. For a proper cleanup we have to ensure
+		that the following code either works and used_l2table contains
+		a valid L2 table - or fails and used_l2table->table contains the
+		list of page pointers. Any mixed contents will make cleanup
+		difficult.*/
+
+		for (i = 0; i < nr_of_pages; i++) {
+			pte_t pte;
+			page = l2table_as_array_of_pointers_to_page[i];
+
+			/* create L2 table entry, see ARM MMU docu for details
+			about flags stored in the lowest 12 bits. As a side
+			reference, the Article "ARM's multiply-mapped memory
+			mess" found in the collection at at
+			http://lwn.net/Articles/409032/ is also worth reading.*/
+			pte = page_to_l2_pte(page)
+					| L2_FLAG_AP1 | L2_FLAG_AP0
+					| L2_FLAG_C | L2_FLAG_B
+					| L2_FLAG_SMALL | L2_FLAG_SMALL_XN
+			/* Linux uses different mappings for SMP systems(the
+			 * sharing flag is set for the pte. In order not to
+			 * confuse things too much in Mobicore make sure the
+			 * shared buffers have the same flags.
+			 * This should also be done in SWD side
+			 */
+#ifdef CONFIG_SMP
+					| L2_FLAG_S | L2_FLAG_SMALL_TEX0
+#endif
+				  ;
+
+			l2table->table_entries[i] = pte;
+			MCDRV_DBG_VERBOSE("L2 entry %d:  0x%08x\n", i,
+					  (unsigned int)(pte));
+		}
+
+		/* ensure rest of table is empty */
+		while (i < 255)
+			l2table->table_entries[i++] = (pte_t)0;
+
+	} while (FALSE);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Remove a L2 table in a WSM container. Afterwards the container may be
+ * released.
+ *
+ * @param used_l2table	Pointer to L2 table details
+ */
+
+static void unmap_buffers_from_used_l2_table(
+	struct mc_used_l2_table	*used_l2table
+)
+{
+	unsigned int	i;
+	struct l2table	*l2table;
+
+	MCDRV_ASSERT(used_l2table != NULL);
+	/* this should not happen, as we have no empty tables. */
+	MCDRV_ASSERT(!is_in_use_used_l2_table(used_l2table));
+
+	/* found the table, now release the resources. */
+	MCDRV_DBG_VERBOSE("clear L2 table, phys_base=%p, nr_of_pages=%d\n",
+			  get_l2_table_phys(used_l2table),
+			  used_l2table->nr_of_pages);
+
+	l2table = get_l2_table_kernel_virt(used_l2table);
+
+	/* release all locked user space pages */
+	for (i = 0; i < used_l2table->nr_of_pages; i++) {
+		/* convert physical entries from L2 table to page pointers */
+		pte_t pte = get_l2_table_kernel_virt(used_l2table)->
+							table_entries[i];
+		struct page *page = l2_pte_to_page(pte);
+		unlock_page_from_used_l2_table(page);
+	}
+
+	/* remember that all pages have been freed */
+	used_l2table->nr_of_pages = 0;
+
+	return;
+}
+
+
+/*
+#############################################################################
+##
+## Helper functions
+##
+#############################################################################*/
+/*----------------------------------------------------------------------------*/
+#define FREE_FROM_SWD	TRUE
+#define FREE_FROM_NWD	FALSE
+/** Delete a used l2 table. */
+static void delete_used_l2_table(
+	struct mc_used_l2_table	*used_l2table,
+	unsigned int		is_swd
+)
+{
+	if (is_swd) {
+		used_l2table->flags &=
+			~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+	} else {
+		used_l2table->flags &=
+			~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP;
+		used_l2table->owner = NULL;
+	}
+
+	/* release if Nwd and Swd/MC do no longer use it. */
+	if (is_in_use_used_l2_table(used_l2table)) {
+		MCDRV_DBG_WARN(
+			"WSM L2 table still in use: physBase=%p, "
+			"nr_of_pages=%d\n",
+			get_l2_table_phys(used_l2table),
+			used_l2table->nr_of_pages);
+	} else {
+		unmap_buffers_from_used_l2_table(used_l2table);
+		free_used_l2_table(used_l2table);
+
+		list_del(&(used_l2table->list));
+
+		kfree(used_l2table);
+	}
+	return;
+}
+
+/*----------------------------------------------------------------------------*/
+/** Allocate L2 table and map buffer into it. That is, create respective table
+	entries. Must hold Semaphore mc_drv_kmod_ctx.wsm_l2_sem */
+static struct mc_used_l2_table *new_used_l2_table(
+	struct mc_instance	*instance,
+	struct task_struct	*task,
+	void			*wsm_buffer,
+	unsigned int		wsm_len
+) {
+	int			ret = 0;
+	struct mc_used_l2_table	*used_l2table;
+
+	do {
+		used_l2table = allocate_used_l2_table(instance);
+		if (used_l2table == NULL) {
+			MCDRV_DBG_ERROR(
+				"allocate_used_l2_table() failed\n");
+			break;
+		}
+
+		/* create the L2 page for the WSM */
+		ret = map_buffer_into_used_l2_table(
+				  task,
+				  wsm_buffer,
+				  wsm_len,
+				  used_l2table);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR(
+				"map_buffer_into_used_l2_table() failed\n");
+			delete_used_l2_table(used_l2table, FREE_FROM_NWD);
+			used_l2table = NULL;
+			break;
+		}
+
+	} while (FALSE);
+
+
+	return used_l2table;
+}
+
+/*
+#############################################################################
+##
+## IoCtl handler
+##
+#############################################################################*/
+
+/**
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr		address of the buffer(NB it must be kernel virtual!)
+ * @param len		buffer length
+ * @param handle	pointer to handle
+ * @param phys_wsm_l2_table	pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+/*----------------------------------------------------------------------------*/
+int mobicore_map_vmem(
+	struct mc_instance	*instance,
+	void			*addr,
+	uint32_t		len,
+	uint32_t		*handle,
+	void			**phys_wsm_l2_table
+)
+{
+	int ret = 0;
+	struct mc_used_l2_table *used_l2table = NULL;
+	MCDRV_ASSERT(instance != NULL);
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		if (len == 0) {
+			MCDRV_DBG_ERROR("len=0 is not supported!\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table = new_used_l2_table(
+						   instance,
+						   NULL,
+						   addr,
+						   len);
+
+			if (used_l2table == NULL) {
+				MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
+				ret = -EINVAL;
+				break;
+			}
+
+			/* set response */
+			*handle = used_l2table->handle;
+			*phys_wsm_l2_table =
+				(void *)get_l2_table_phys(used_l2table);
+			MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n",
+					  *handle,
+					  (void *)(*phys_wsm_l2_table));
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_map_vmem);
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_app_register_wsm_l2(
+	struct mc_instance			*instance,
+	union mc_ioctl_app_reg_wsm_l2_params	*user_params
+)
+{
+	int					ret = 0;
+	union mc_ioctl_app_reg_wsm_l2_params	params;
+	struct mc_used_l2_table			*used_l2table = NULL;
+	struct pid				*pid_struct = NULL;
+	struct task_struct			*task = current;
+
+	MCDRV_ASSERT(instance != NULL);
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* get use parameters */
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user() failed\n");
+			break;
+		}
+
+		/* daemon can do this for another task. */
+		if (params.in.pid != 0) {
+			MCDRV_DBG_ERROR("pid != 0 unsupported\n");
+			ret = -EINVAL;
+			break;
+		}
+		if (params.in.len == 0) {
+			MCDRV_DBG_ERROR("len=0 is not supported!\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table = new_used_l2_table(
+						   instance,
+						   task,
+						   (void *)(params.in.buffer),
+						   params.in.len);
+
+			if (used_l2table == NULL) {
+				MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
+				ret = -EINVAL;
+				break;
+			}
+
+			/* if the daemon does this, we set the MC lock */
+			if (is_caller_mc_daemon(instance))
+				used_l2table->flags |=
+					MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+
+			/* set response */
+			memset(&params.out, 0, sizeof(params.out));
+			params.out.handle = used_l2table->handle;
+			/* TODO: return the physical address for daemon only,
+				otherwise set NULL */
+			params.out.phys_wsm_l2_table =
+				(uint32_t)get_l2_table_phys(used_l2table);
+
+			MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n",
+					params.out.handle,
+					(void *)(params.out.phys_wsm_l2_table));
+
+
+			/* copy L2Table to user space */
+			ret = copy_to_user(
+					  &(user_params->out),
+					  &(params.out),
+					  sizeof(params.out));
+			if (ret != 0) {
+				MCDRV_DBG_ERROR("copy_to_user() failed\n");
+
+				/* free the table again, as app does not know
+					about anything. */
+				if (is_caller_mc_daemon(instance)) {
+					used_l2table->flags &=
+					~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+				}
+				delete_used_l2_table(used_l2table,
+						FREE_FROM_NWD);
+				used_l2table = NULL;
+				break;
+			}
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+
+
+	/* release PID struct reference */
+	if (pid_struct != NULL)
+		put_pid(pid_struct);
+
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(
+	struct mc_instance	*instance,
+	uint32_t		handle
+)
+{
+	int ret = 0;
+	struct mc_used_l2_table *used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("processOpenSession() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table = find_used_l2_table_by_handle(handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+
+			if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* free table (if no further locks exist) */
+			delete_used_l2_table(used_l2table, FREE_FROM_NWD);
+			used_l2table = NULL;
+			/* there are no out parameters */
+		} while (FALSE);
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_unmap_vmem);
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_app_unregister_wsm_l2(
+	struct mc_instance			*instance,
+	struct mc_ioctl_app_unreg_wsm_l2_params	*user_params
+)
+{
+	int					ret = 0;
+	struct mc_ioctl_app_unreg_wsm_l2_params	params;
+	struct mc_used_l2_table			*used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			/* daemon can do this for another task. */
+			if (params.in.pid != 0) {
+				MCDRV_DBG_ERROR("pid != 0 unsupported\n");
+				ret = -EINVAL;
+				break;
+			}
+
+			used_l2table =
+				find_used_l2_table_by_handle(params.in.handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+
+			if (is_caller_mc_daemon(instance)) {
+				/* if daemon does this, we have to release the
+					MobiCore lock. */
+				used_l2table->flags &=
+					~MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+			} else if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* free table (if no further locks exist) */
+			delete_used_l2_table(used_l2table, FREE_FROM_NWD);
+			used_l2table = NULL;
+
+			/* there are no out parameters */
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static int handle_ioctl_daemon_lock_wsm_l2(
+	struct mc_instance				*instance,
+	struct mc_ioctl_daemon_lock_wsm_l2_params	*user_params
+)
+{
+	int						ret = 0;
+	struct mc_ioctl_daemon_lock_wsm_l2_params	params;
+	struct mc_used_l2_table				*used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+					ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table =
+				find_used_l2_table_by_handle(params.in.handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+			if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* lock entry */
+			if ((used_l2table->flags &
+				  MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) != 0) {
+				MCDRV_DBG_WARN("entry already locked\n");
+			}
+			used_l2table->flags |=
+				MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+
+			/* prepare response */
+			memset(&(params.out), 0, sizeof(params.out));
+			params.out.phys_wsm_l2_table =
+				(uint32_t)get_l2_table_phys(used_l2table);
+
+			/* copy to user space */
+			ret = copy_to_user(
+					  &(user_params->out),
+					  &(params.out),
+					  sizeof(params.out));
+			if (ret != 0) {
+				MCDRV_DBG_ERROR("copy_to_user() failed\n");
+
+				/* undo, as userspace did not get it. */
+				used_l2table->flags |=
+					MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC;
+				break;
+			}
+
+		} while (FALSE);
+
+		/* release semaphore */
+		up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static int handle_ioctl_daemon_unlock_wsm_l2(
+	struct mc_instance				*instance,
+	struct mc_ioctl_daemon_unlock_wsm_l2_params	*user_params
+)
+{
+	int						ret = 0;
+	struct mc_ioctl_daemon_unlock_wsm_l2_params	params;
+	struct mc_used_l2_table				*used_l2table = NULL;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("down_interruptible() failed with %d\n",
+						ret);
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		do {
+			used_l2table =
+				find_used_l2_table_by_handle(params.in.handle);
+			if (used_l2table == NULL) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("entry not found\n");
+				break;
+			}
+			if (instance != used_l2table->owner) {
+				ret = -EINVAL;
+				MCDRV_DBG_ERROR("instance does no own it\n");
+				break;
+			}
+
+			/* lock entry */
+			if ((used_l2table->flags &
+				  MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC) == 0) {
+				MCDRV_DBG_WARN("entry is not locked locked\n");
+			}
+
+			/* free table (if no further locks exist) */
+			delete_used_l2_table(used_l2table, FREE_FROM_SWD);
+			used_l2table = NULL;
+
+			/* there are no out parameters */
+
+		} while (FALSE);
+
+	} while (FALSE);
+
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/** Clears the reserved bit of each page and frees the pages */
+static inline void free_continguous_pages(
+	void		*addr,
+	unsigned int	size
+)
+{
+	struct page *page = virt_to_page(addr);
+	int i;
+	for (i = 0; i < size; i++) {
+		MCDRV_DBG_VERBOSE("free page at 0x%p\n", page);
+		ClearPageReserved(page);
+		page++;
+	}
+	/* REV luh: see man kmalloc */
+	free_pages((unsigned long)addr, size_to_order(size));
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle		handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free(
+	struct mc_instance	*instance,
+	uint32_t		handle
+)
+{
+	int ret = 0;
+	unsigned int i;
+	struct mc_contg_buffer	*contg_buffer;
+
+	do {
+		/* search for the given address in the contg_buffers list */
+		for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
+			contg_buffer = &(instance->contg_buffers[i]);
+			if (contg_buffer->handle == handle)
+				break;
+		}
+		if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
+			MCDRV_DBG_ERROR("contigous buffer not found\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		MCDRV_DBG_VERBOSE("phys_addr=0x%p, virt_addr=0x%p\n",
+				contg_buffer->phys_addr,
+				contg_buffer->virt_kernel_addr);
+
+		free_continguous_pages(contg_buffer->virt_kernel_addr,
+					contg_buffer->num_pages);
+
+		memset(contg_buffer, 0, sizeof(*contg_buffer));
+
+		/* there are no out parameters */
+
+	} while (FALSE);
+
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_free);
+/*----------------------------------------------------------------------------*/
+
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_free(
+	struct mc_instance		*instance,
+	union mc_ioctl_free_params	*user_params
+)
+{
+	int				ret = 0;
+	union mc_ioctl_free_params	params;
+
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+
+		/* daemon can do this for another task. */
+		if (params.in.pid != 0) {
+			MCDRV_DBG_ERROR("pid != 0 unsupported\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		ret = mobicore_free(instance, params.in.handle);
+
+		/* there are no out parameters */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_info(
+	struct mc_instance	*instance,
+	union mc_ioctl_info_params	*user_params
+)
+{
+	int			ret = 0;
+	union mc_ioctl_info_params	params;
+	union mc_fc_info		fc_info;
+
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user\n");
+			break;
+		}
+
+
+		memset(&fc_info, 0, sizeof(fc_info));
+		fc_info.as_in.cmd	   = MC_FC_INFO;
+		fc_info.as_in.ext_info_id = params.in.ext_info_id;
+
+		MCDRV_DBG(
+			"fc_info in cmd=0x%08x, ext_info_id=0x%08x "
+			"rfu=(0x%08x, 0x%08x)\n",
+			fc_info.as_in.cmd,
+			fc_info.as_in.ext_info_id,
+			fc_info.as_in.rfu[0],
+			fc_info.as_in.rfu[1]);
+
+		mc_fastcall(&(fc_info.as_generic));
+
+		MCDRV_DBG(
+			"fc_info out resp=0x%08x, ret=0x%08x "
+			"state=0x%08x, ext_info=0x%08x\n",
+			fc_info.as_out.resp,
+			fc_info.as_out.ret,
+			fc_info.as_out.state,
+			fc_info.as_out.ext_info);
+
+		ret = convert_fc_ret(fc_info.as_out.ret);
+		if (ret != 0)
+			break;
+
+		memset(&(params.out), 0, sizeof(params.out));
+		params.out.state  = fc_info.as_out.state;
+		params.out.ext_info = fc_info.as_out.ext_info;
+
+		ret = copy_to_user(
+				  &(user_params->out),
+				  &(params.out),
+				  sizeof(params.out));
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_to_user\n");
+			break;
+		}
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_yield(
+	struct mc_instance	*instance
+)
+{
+	int			ret = 0;
+	union mc_fc_s_yield	fc_s_yield;
+
+	MCDRV_ASSERT(instance != NULL);
+
+	/* avoid putting debug output here, as we do this very often */
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		memset(&fc_s_yield, 0, sizeof(fc_s_yield));
+		fc_s_yield.as_in.cmd = MC_SMC_N_YIELD;
+		mc_fastcall(&(fc_s_yield.as_generic));
+		ret = convert_fc_ret(fc_s_yield.as_out.ret);
+		if (ret != 0)
+			break;
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * handle ioctl and call common notify
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_nsiq(
+	struct mc_instance	*instance,
+	unsigned long		arg
+)
+{
+	int		ret = 0;
+
+	MCDRV_ASSERT(instance != NULL);
+
+	/* avoid putting debug output here, as we do this very often */
+	MCDRV_DBG_VERBOSE("enter\n");
+	/* only the MobiCore Daemon is allowed to call this function */
+	if (!is_caller_mc_daemon(instance)) {
+		MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+		return -EFAULT;
+	}
+
+	do {
+		union mc_fc_nsiq fc_nsiq;
+		memset(&fc_nsiq, 0, sizeof(fc_nsiq));
+		fc_nsiq.as_in.cmd = MC_SMC_N_SIQ;
+		mc_fastcall(&(fc_nsiq.as_generic));
+		ret = convert_fc_ret(fc_nsiq.as_out.ret);
+		if (ret != 0)
+			break;
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_dump_status(
+	struct mc_instance	*instance,
+	unsigned long		arg
+)
+{
+	int		ret = 0;
+	int		i = 0;
+	union mc_fc_info	fc_info;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* anybody with root access can do this. */
+		if (!is_userland_caller_privileged()) {
+			MCDRV_DBG_ERROR("caller must have root privileges\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		/* loop ext_info */
+		while (TRUE) {
+			memset(&fc_info, 0, sizeof(fc_info));
+			fc_info.as_in.cmd	   = MC_FC_INFO;
+			fc_info.as_in.ext_info_id = i;
+
+			MCDRV_DBG(
+				"fc_info in cmd=0x%08x, ext_info_id=0x%08x "
+				"rfu=(0x%08x, 0x%08x)\n",
+				fc_info.as_in.cmd,
+				fc_info.as_in.ext_info_id,
+				fc_info.as_in.rfu[0],
+				fc_info.as_in.rfu[1]);
+
+			mc_fastcall(&(fc_info.as_generic));
+
+			MCDRV_DBG(
+				"fc_info out resp=0x%08x, ret=0x%08x "
+				"state=0x%08x, ext_info=0x%08x\n",
+				fc_info.as_out.resp,
+				fc_info.as_out.ret,
+				fc_info.as_out.state,
+				fc_info.as_out.ext_info);
+
+			ret = convert_fc_ret(fc_info.as_out.ret);
+			if (ret != 0)
+				break;
+
+			MCDRV_DBG("state=%08X, idx=%02d: ext_info=%08X\n",
+				fc_info.as_out.state,
+				i,
+				fc_info.as_out.ext_info);
+			i++;
+		};
+
+		if (ret != 0)
+			break;
+
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_init(
+	struct mc_instance	*instance,
+	union mc_ioctl_init_params	*user_params
+)
+{
+	int			ret = 0;
+	union mc_ioctl_init_params	params;
+	union mc_fc_init		fc_init;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user failed\n");
+			break;
+		}
+
+		memset(&fc_init, 0, sizeof(fc_init));
+
+		fc_init.as_in.cmd	= MC_FC_INIT;
+		/* base address of mci buffer 4KB aligned */
+		fc_init.as_in.base   = (uint32_t)params.in.base;
+		/* notification buffer start/length [16:16] [start, length] */
+		fc_init.as_in.nq_info  = (params.in.nq_offset << 16)
+					  | (params.in.nq_length & 0xFFFF);
+		/* mcp buffer start/length [16:16] [start, length] */
+		fc_init.as_in.mcp_info = (params.in.mcp_offset << 16)
+					  | (params.in.mcp_length & 0xFFFF);
+
+		/* Set KMOD notification queue to start of MCI
+			mciInfo was already set up in mmap */
+		if (!mci_base) {
+			MCDRV_DBG_ERROR("No MCI set yet.\n");
+			return -EFAULT;
+		}
+		MCDRV_DBG("in cmd=0x%08x, base=0x%08x, "
+			  "nq_info=0x%08x, mcp_info=0x%08x\n",
+			  fc_init.as_in.cmd,
+			  fc_init.as_in.base,
+			  fc_init.as_in.nq_info,
+			  fc_init.as_in.mcp_info);
+
+		mc_fastcall(&(fc_init.as_generic));
+
+		MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n",
+			  fc_init.as_out.resp,
+			  fc_init.as_out.ret,
+			  fc_init.as_out.rfu[0],
+			  fc_init.as_out.rfu[1]);
+
+		ret = convert_fc_ret(fc_init.as_out.ret);
+		if (ret != 0)
+			break;
+
+		/* no ioctl response parameters */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_fc_execute(
+	struct mc_instance		*instance,
+	union mc_ioctl_fc_execute_params	*user_params
+)
+{
+	int				ret = 0;
+	union mc_ioctl_fc_execute_params	params;
+	union fc_generic			fc_params;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = copy_from_user(
+				  &(params.in),
+				  &(user_params->in),
+				  sizeof(params.in));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_from_user failed\n");
+			break;
+		}
+
+		fc_params.as_in.cmd = -4;/*FC_EXECUTE */
+		fc_params.as_in.param[0] = params.in.phys_start_addr;
+		fc_params.as_in.param[1] = params.in.length;
+		fc_params.as_in.param[2] = 0;
+
+		MCDRV_DBG("in cmd=0x%08x, startAddr=0x%08x, length=0x%08x\n",
+			  fc_params.as_in.cmd,
+			  fc_params.as_in.param[0],
+			  fc_params.as_in.param[1]);
+
+		mc_fastcall(&fc_params);
+
+		MCDRV_DBG("out cmd=0x%08x, ret=0x%08x rfu=(0x%08x, 0x%08x)\n",
+			  fc_params.as_out.resp,
+			  fc_params.as_out.ret,
+			  fc_params.as_out.param[0],
+			  fc_params.as_out.param[1]);
+
+		ret = convert_fc_ret(fc_params.as_out.ret);
+		if (ret != 0)
+			break;
+
+		/* no ioctl response parameters */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+#define MC_MAKE_VERSION(major, minor) \
+		(((major & 0x0000ffff) << 16) | (minor & 0x0000ffff))
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+static int handle_ioctl_get_version(
+	struct mc_instance			*instance,
+	struct mc_ioctl_get_version_params	*user_params
+)
+{
+	int ret = 0;
+	struct mc_ioctl_get_version_params params = {
+		{
+			MC_MAKE_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
+					MCDRVMODULEAPI_VERSION_MINOR)
+		}
+	};
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
+				MCDRVMODULEAPI_VERSION_MAJOR,
+				MCDRVMODULEAPI_VERSION_MINOR);
+
+		/* no ioctl response parameters */
+		ret = copy_to_user(
+					&(user_params->out),
+					&(params.out),
+					sizeof(params.out));
+		if (ret != 0)
+			MCDRV_DBG_ERROR("copy_to_user() failed\n");
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as ioctl(...).
+ * @param file	pointer to file
+ * @param cmd	command
+ * @param arg	arguments
+ *
+ * @return int 0 for OK and an errno in case of error
+ */
+static long mc_kernel_module_ioctl(
+	struct file	*file,
+	unsigned int	cmd,
+	unsigned long	arg
+)
+{
+	int ret;
+	struct mc_instance *instance = get_instance(file);
+
+	MCDRV_ASSERT(instance != NULL);
+
+	switch (cmd) {
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_DUMP_STATUS:
+		ret = handle_ioctl_dump_status(
+				instance,
+				arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_INIT:
+		ret = handle_ioctl_init(
+				instance,
+				(union mc_ioctl_init_params *)arg);
+		break;
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_INFO:
+		ret = handle_ioctl_info(
+				instance,
+				(union mc_ioctl_info_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_YIELD:
+		ret = handle_ioctl_yield(
+				instance);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_NSIQ:
+		ret = handle_ioctl_nsiq(
+				instance,
+				arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2:
+		ret = handle_ioctl_daemon_lock_wsm_l2(
+			instance,
+			(struct mc_ioctl_daemon_lock_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2:
+		ret = handle_ioctl_daemon_unlock_wsm_l2(
+			instance,
+			(struct mc_ioctl_daemon_unlock_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FREE:
+		/* called by ClientLib */
+		ret = handle_ioctl_free(
+				instance,
+				(union mc_ioctl_free_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2:
+		/* called by ClientLib */
+		ret = handle_ioctl_app_register_wsm_l2(
+				instance,
+				(union mc_ioctl_app_reg_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2:
+		/* called by ClientLib */
+		ret = handle_ioctl_app_unregister_wsm_l2(
+				instance,
+				(struct mc_ioctl_app_unreg_wsm_l2_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_FC_EXECUTE:
+		ret = handle_ioctl_fc_execute(
+				instance,
+				(union mc_ioctl_fc_execute_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	case MC_DRV_KMOD_IOCTL_GET_VERSION:
+		ret = handle_ioctl_get_version(
+				instance,
+				(struct mc_ioctl_get_version_params *)arg);
+		break;
+
+	/*--------------------------------------------------------------------*/
+	default:
+		MCDRV_DBG_ERROR("unsupported cmd=%d\n", cmd);
+		ret = -EFAULT;
+		break;
+
+	} /* end switch(cmd) */
+
+#ifdef MC_MEM_TRACES
+	mobicore_log_read();
+#endif
+
+	return (int)ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as read(...).
+ * The read function is blocking until a interrupt occurs. In that case the
+ * event counter is copied into user space and the function is finished.
+ * @param *file
+ * @param *buffer  buffer where to copy to(userspace)
+ * @param buffer_len	 number of requested data
+ * @param *pos	 not used
+ * @return ssize_t  ok case: number of copied data
+ *				error case: return errno
+ */
+static ssize_t mc_kernel_module_read(
+	struct file	*file,
+	char		*buffer,
+	size_t		buffer_len,
+	loff_t		*pos
+)
+{
+	int ret = 0, ssiq_counter;
+	size_t retLen = 0;
+	struct mc_instance *instance = get_instance(file);
+
+	MCDRV_ASSERT(instance != NULL);
+
+	/* avoid debug output on non-error, because this is call quite often */
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* only the MobiCore Daemon is allowed to call this function */
+		if (!is_caller_mc_daemon(instance)) {
+			MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		if (buffer_len < sizeof(unsigned int)) {
+			MCDRV_DBG_ERROR("invalid length\n");
+			ret = (ssize_t)(-EINVAL);
+			break;
+		}
+
+		for (;;) {
+			if (down_interruptible(
+					&mc_drv_kmod_ctx.daemon_ctx.sem)) {
+				MCDRV_DBG_VERBOSE("read interrupted\n");
+				ret = (ssize_t)-ERESTARTSYS;
+				break;
+			}
+
+			ssiq_counter = atomic_read(
+					&(mc_drv_kmod_ctx.ssiq_ctx.counter));
+			MCDRV_DBG_VERBOSE("ssiq_counter=%i, ctx.counter=%i\n",
+				ssiq_counter,
+				mc_drv_kmod_ctx.daemon_ctx.ssiq_counter);
+
+			if (ssiq_counter !=
+				mc_drv_kmod_ctx.daemon_ctx.ssiq_counter) {
+				/* read data and exit loop without
+					error */
+				mc_drv_kmod_ctx.daemon_ctx.ssiq_counter =
+					ssiq_counter;
+				ret = 0;
+				break;
+			}
+
+			/* end loop if non-blocking */
+			if ((file->f_flags & O_NONBLOCK) != 0) {
+				MCDRV_DBG_ERROR("non-blocking read\n");
+				ret = (ssize_t)(-EAGAIN);
+				break;
+			}
+
+			if (signal_pending(current) != 0) {
+				MCDRV_DBG_VERBOSE("received signal.\n");
+				ret = (ssize_t)(-ERESTARTSYS);
+				break;
+			}
+
+		}
+
+		/* we are here if an event occurred or we had an
+			error.*/
+		if (ret != 0)
+			break;
+
+		/* read data and exit loop */
+		ret = copy_to_user(
+				  buffer,
+				  &(mc_drv_kmod_ctx.daemon_ctx.ssiq_counter),
+				  sizeof(unsigned int));
+
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("copy_to_user failed\n");
+			ret = (ssize_t)(-EFAULT);
+			break;
+		}
+
+		retLen = sizeof(s32);
+
+	} while (FALSE);
+
+	/* avoid debug on non-error. */
+	if (ret == 0)
+		ret = (size_t)retLen;
+	else
+		MCDRV_DBG("exit with %d/0x%08X\n", ret, ret);
+
+	return (ssize_t)ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Allocate WSM for given instance
+ *
+ * @param instance		instance
+ * @param requested_size		size of the WSM
+ * @param handle		pointer where the handle will be saved
+ * @param virt_kernel_addr	pointer for the kernel virtual address
+ * @param phys_addr		pointer for the physical address
+ *
+ * @return error code or 0 for success
+ */
+int mobicore_allocate_wsm(
+	struct mc_instance	*instance,
+	unsigned long		requested_size,
+	uint32_t		*handle,
+	void			**virt_kernel_addr,
+	void			**phys_addr
+)
+{
+	unsigned int	i;
+	unsigned int	order;
+	unsigned long	allocated_size;
+	int		ret = 0;
+	struct mc_contg_buffer	*contg_buffer = 0;
+	void		*virt_kernel_addr_stack;
+	void		*phys_addr_stack;
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG("%s (size=%ld)\n", __func__, requested_size);
+
+	order = size_to_order(requested_size);
+	if (order == INVALID_ORDER) {
+		MCDRV_DBG_ERROR(
+			"size to order converting failed for size %ld\n",
+			requested_size);
+		return INVALID_ORDER;
+	}
+
+	allocated_size = (1<<order)*PAGE_SIZE;
+
+	MCDRV_DBG("size %ld -> order %d --> %ld (2^n pages)\n",
+		  requested_size, order, allocated_size);
+
+	do {
+		/* Usual Wsm request, allocate contigous buffer. */
+		/* search for a free entry in the wsm buffer list
+		 * REV axh: serialize this over multiple instances. */
+		for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
+			contg_buffer = &(instance->contg_buffers[i]);
+			if (contg_buffer->handle == 0) {
+				contg_buffer->handle = get_mc_kmod_unique_id();
+				break;
+			}
+		}
+		if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
+			MCDRV_DBG_ERROR("no free contigous buffer\n");
+			ret = -EFAULT;
+			break;
+		}
+
+		/* Common code for all allocation paths */
+		virt_kernel_addr_stack = (void *)__get_free_pages(
+							GFP_USER | __GFP_COMP,
+							order);
+		if (virt_kernel_addr_stack == NULL) {
+			MCDRV_DBG_ERROR("get_free_pages failed\n");
+			ret = -ENOMEM;
+			break;
+		}
+
+		/* Get physical address to instance data */
+		phys_addr_stack = (void *)virt_to_phys(virt_kernel_addr_stack);
+		/* TODO: check for INVALID_ADDRESS? */
+
+		MCDRV_DBG(
+			"allocated phys=0x%p - 0x%p, "
+			"size=%ld, kernel_virt=0x%p, handle=%d\n",
+			phys_addr_stack,
+			(void *)((unsigned int)phys_addr_stack+allocated_size),
+			allocated_size,
+			virt_kernel_addr_stack,
+			contg_buffer->handle);
+
+		/* Usual Wsm request, allocate contg_buffer.
+		 *		Also, we never free a persistent Tci */
+		contg_buffer->phys_addr	 = phys_addr_stack;
+		contg_buffer->virt_kernel_addr = virt_kernel_addr_stack;
+		contg_buffer->virt_user_addr   = virt_kernel_addr_stack;
+		contg_buffer->num_pages	 = (1U << order);
+		*handle = contg_buffer->handle;
+		*virt_kernel_addr = virt_kernel_addr_stack;
+		*phys_addr = phys_addr_stack;
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("%s: exit with 0x%08X\n", __func__, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_allocate_wsm);
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as address = mmap(...).
+ *
+ * @param file
+ * @param vmarea
+ * vmarea.pg_offset != 0 is mapping of MCI is requested
+ *
+ * @return 0 if OK or -ENOMEM in case of error.
+ */
+static int mc_kernel_module_mmap(
+	struct file		*file,
+	struct vm_area_struct	*vmarea
+)
+{
+	unsigned int		i;
+	unsigned int		order;
+	void			*virt_kernel_addr_stack = 0;
+	void			*phys_addr = 0;
+	unsigned long		requested_size =
+					vmarea->vm_end - vmarea->vm_start;
+	unsigned long		allocated_size;
+	int			ret = 0;
+	struct mc_contg_buffer	*contg_buffer = 0;
+	unsigned int		handle = 0;
+	struct mc_instance	*instance = get_instance(file);
+	unsigned int		request = vmarea->vm_pgoff * 4096;
+#if defined(DEBUG)
+	bool release = false;
+#else
+	bool release = true;
+#endif
+
+	MCDRV_ASSERT(instance != NULL);
+	MCDRV_DBG("enter (vmaStart=0x%p, size=%ld, request=0x%x, mci=0x%x)\n",
+		  (void *)vmarea->vm_start,
+		  requested_size,
+		  request,
+		  mci_base);
+
+	order = size_to_order(requested_size);
+	if (order == INVALID_ORDER) {
+		MCDRV_DBG_ERROR(
+			"size to order converting failed for size %ld\n",
+			requested_size);
+		return -ENOMEM;
+	}
+
+	allocated_size = (1<<order)*PAGE_SIZE;
+
+	MCDRV_DBG("size %ld -> order %d --> %ld (2^n pages)\n",
+		  requested_size, order, allocated_size);
+
+	do {
+		/* Daemon tries to get an existing MCI */
+		if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base != 0)) {
+			MCDRV_DBG("Request MCI, it is at (%x)\n", mci_base);
+
+			if (!is_caller_mc_daemon(instance)) {
+				ret = -EPERM;
+				break;
+			}
+			virt_kernel_addr_stack = (void *)mci_base;
+			phys_addr =
+				(void *)virt_to_phys(virt_kernel_addr_stack);
+		} else {
+			/* Usual Wsm request, allocate buffer. */
+			if (request == MC_DRV_KMOD_MMAP_WSM) {
+				/* search for a free entry in the buffer list
+				REV axh: serialize this over multiple instances.
+				*/
+				for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX;
+					i++) {
+					contg_buffer =
+						&(instance->contg_buffers[i]);
+					if (contg_buffer->handle == 0) {
+						contg_buffer->handle =
+							get_mc_kmod_unique_id();
+						break;
+					}
+				}
+				if (i == MC_DRV_KMOD_CONTG_BUFFER_MAX) {
+					MCDRV_DBG_ERROR(
+						"no free contigous buffer\n");
+					ret = -EFAULT;
+					break;
+				}
+			} else {
+				if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM
+					|| release) {
+					/* Special Wsm request
+						--> only Daemon is allowed */
+					if (!is_caller_mc_daemon(instance)) {
+						ret = -EPERM;
+						break;
+					}
+				}
+			}
+			if (request <= MC_DRV_KMOD_MMAP_PERSISTENTWSM) {
+				/* Common code for all allocation paths
+					*  get physical address, */
+				virt_kernel_addr_stack =
+					(void *)__get_free_pages(
+							GFP_USER | __GFP_COMP,
+							order);
+				if (virt_kernel_addr_stack == NULL) {
+					MCDRV_DBG_ERROR(
+						"get_free_pages failed\n");
+					ret = -ENOMEM;
+					break;
+				}
+				if (request == MC_DRV_KMOD_MMAP_WSM)
+					handle = contg_buffer->handle;
+				/* Get physical address to instance data */
+				/* TODO: check for INVALID_ADDRESS? */
+				phys_addr = (void *)virt_to_phys(
+							virt_kernel_addr_stack);
+			} else {
+#if defined(DEBUG)
+				phys_addr = (void *)request;
+				virt_kernel_addr_stack = phys_to_virt(request);
+#endif
+			}
+		}
+		/* Common code for all mmap calls:
+		 * map page to user
+		 * store data in page */
+
+		MCDRV_DBG("allocated phys=0x%p - 0x%p, "
+			"size=%ld, kernel_virt=0x%p, handle=%d\n",
+			phys_addr,
+			(void *)((unsigned int)phys_addr+allocated_size),
+			allocated_size, virt_kernel_addr_stack, handle);
+
+		vmarea->vm_flags |= VM_RESERVED;
+		/* convert Kernel address to User Address. Kernel address begins
+			at PAGE_OFFSET, user Address range is below PAGE_OFFSET.
+			Remapping the area is always done, so multiple mappings
+			of one region are possible. Now remap kernel address
+			space into user space */
+		ret = (int)remap_pfn_range(
+				vmarea,
+				(vmarea->vm_start),
+				addr_to_pfn(phys_addr),
+				requested_size,
+				vmarea->vm_page_prot);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("remapPfnRange failed\n");
+
+			/* free allocated pages when mmap fails, however, do not
+				do it, when daemon tried to get an MCI that
+				existed */
+			if (!((request == MC_DRV_KMOD_MMAP_MCI) &&
+				  (mci_base != 0)))
+				free_continguous_pages(virt_kernel_addr_stack,
+							(1U << order));
+			break;
+		}
+
+		/* Usual Wsm request, allocate contg_buffer.
+			When requesting Mci, we do not associate the page with
+			the process.
+			Note: we also never free the Mci
+			Also, we never free a persistent Tci */
+		if (request == MC_DRV_KMOD_MMAP_WSM) {
+			contg_buffer->phys_addr = phys_addr;
+			contg_buffer->virt_kernel_addr = virt_kernel_addr_stack;
+			contg_buffer->virt_user_addr =
+						(void *)(vmarea->vm_start);
+			contg_buffer->num_pages = (1U << order);
+		}
+
+		/* set response in allocated buffer */
+		{
+			struct mc_mmap_resp *mmap_resp =
+				(struct mc_mmap_resp *)virt_kernel_addr_stack;
+			/* TODO: do this for daemon only, otherwise set NULL */
+			mmap_resp->phys_addr = (uint32_t)phys_addr;
+			mmap_resp->handle = handle;
+			if ((request == MC_DRV_KMOD_MMAP_MCI) &&
+				(mci_base != 0)) {
+				mmap_resp->is_reused = 1;
+			} else
+				mmap_resp->is_reused = 0;
+		}
+
+		/* store MCI pointer */
+		if ((request == MC_DRV_KMOD_MMAP_MCI) && (mci_base == 0)) {
+			mci_base = (uint32_t)virt_kernel_addr_stack;
+			MCDRV_DBG("MCI base set to 0x%x\n", mci_base);
+		}
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+}
+
+#ifdef CONFIG_SMP
+/*----------------------------------------------------------------------------*/
+/**
+ * Force migration of current task to CPU0(where the monitor resides)
+ *
+ * @return Error code or 0 for success
+ */
+static int goto_cpu0(
+	void
+)
+{
+	int		ret = 0;
+	struct cpumask	mask =  CPU_MASK_CPU0;
+
+	MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n"
+		  "\tBinding this process to CPU #0.\n"
+		  "\tactive mask is %lx, setting it to mask=%lx\n",
+		  nr_cpu_ids,
+		  raw_smp_processor_id(),
+		  cpu_active_mask->bits[0],
+		  mask.bits[0]);
+	ret = set_cpus_allowed_ptr(current, &mask);
+	if (ret != 0)
+		MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret);
+	MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n",
+				raw_smp_processor_id());
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Restore CPU mask for current to ALL Cpus(reverse of goto_cpu0)
+ *
+ * @return Error code or 0 for success
+ */
+static int goto_all_cpu(
+	void
+)
+{
+	int		ret = 0;
+
+	struct cpumask	mask =  CPU_MASK_ALL;
+
+	MCDRV_DBG_VERBOSE("System has %d CPU's, we are on CPU #%d\n"
+		  "\tBinding this process to CPU #0.\n"
+		  "\tactive mask is %lx, setting it to mask=%lx\n",
+		  nr_cpu_ids,
+		  raw_smp_processor_id(),
+		  cpu_active_mask->bits[0],
+		  mask.bits[0]);
+	ret = set_cpus_allowed_ptr(current, &mask);
+	if (ret != 0)
+		MCDRV_DBG_ERROR("set_cpus_allowed_ptr=%d.\n", ret);
+	MCDRV_DBG_VERBOSE("And now we are on CPU #%d\n",
+				raw_smp_processor_id());
+
+	return ret;
+}
+
+#else
+static int goto_cpu0(void)
+{
+	return 0;
+}
+
+static int goto_all_cpu(void)
+{
+	return 0;
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(
+	void
+) {
+	struct mc_instance	*instance;
+	pid_t			pid_vnr;
+
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (instance == NULL)
+		return NULL;
+
+	/* get a unique ID for this instance (PIDs are not unique) */
+	instance->handle = get_mc_kmod_unique_id();
+
+	/* get the PID of the calling process. We avoid using
+	 *	current->pid directly, as 2.6.24 introduced PID
+	 *	namespaces. See also http://lwn.net/Articles/259217 */
+	pid_vnr = task_pid_vnr(current);
+	instance->pid_vnr = pid_vnr;
+
+	return instance;
+}
+EXPORT_SYMBOL(mobicore_open);
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as fd = open(...).
+ * A set of internal instance data are created and initialized.
+ *
+ * @param inode
+ * @param file
+ * @return 0 if OK or -ENOMEM if no allocation was possible.
+ */
+static int mc_kernel_module_open(
+	struct inode	*inode,
+	struct file	*file
+)
+{
+	struct mc_instance	*instance;
+	int			ret = 0;
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		instance = mobicore_open();
+		if (instance == NULL)
+			return -ENOMEM;
+
+		/* check if Daemon. We simply assume that the first to open us
+			with root privileges must be the daemon. */
+		if ((is_userland_caller_privileged())
+			&& (mc_drv_kmod_ctx.daemon_inst == NULL)) {
+			MCDRV_DBG("accept this as MobiCore Daemon\n");
+
+			/* Set the caller's CPU mask to CPU0*/
+			ret = goto_cpu0();
+			if (ret != 0) {
+				mobicore_release(instance);
+				file->private_data = NULL;
+				MCDRV_DBG("changing core failed!\n");
+				break;
+			}
+
+			mc_drv_kmod_ctx.daemon_inst = instance;
+			sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem,
+					DAEMON_SEM_VAL);
+			/* init ssiq event counter */
+			mc_drv_kmod_ctx.daemon_ctx.ssiq_counter =
+				atomic_read(
+					&(mc_drv_kmod_ctx.ssiq_ctx.counter));
+
+#ifdef MC_MEM_TRACES
+			/* The traces have to be setup on CPU-0 since we must
+			 * do a fastcall to MobiCore. */
+			if (!mci_base)
+				/* Do the work only if MCI base is not
+				 * initialized properly */
+				work_on_cpu(0, mobicore_log_setup, NULL);
+#endif
+		}
+
+		/* store instance data reference */
+		file->private_data = instance;
+
+		/* TODO axh: link all instances to allow clean up? */
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(
+	struct mc_instance	*instance
+)
+{
+	int ret = 0;
+	int i;
+	struct mc_used_l2_table	*used_l2table, *used_l2table_temp;
+
+	do {
+		/* try to get the semaphore */
+		ret = down_interruptible(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		if (ret != 0) {
+			MCDRV_DBG_ERROR(
+				"down_interruptible() failed with %d\n", ret);
+			/* TODO: can be block here? */
+			ret = -ERESTARTSYS;
+		} else {
+			/* Check if some WSM is still in use. */
+			list_for_each_entry_safe(
+				used_l2table,
+				used_l2table_temp,
+				&(mc_drv_kmod_ctx.mc_used_l2_tables),
+				list
+			) {
+				if (used_l2table->owner == instance) {
+					MCDRV_DBG_WARN(
+						"trying to release WSM L2: "
+						"physBase=%p ,nr_of_pages=%d\n",
+						get_l2_table_phys(used_l2table),
+						used_l2table->nr_of_pages);
+
+					/* unlock app usage and free if MobiCore
+					does not use it */
+					delete_used_l2_table(used_l2table,
+							FREE_FROM_NWD);
+				}
+			} /* end while */
+
+			/* release semaphore */
+			up(&(mc_drv_kmod_ctx.wsm_l2_sem));
+		}
+
+
+		/* release all mapped data */
+		for (i = 0; i < MC_DRV_KMOD_CONTG_BUFFER_MAX; i++) {
+			struct mc_contg_buffer *contg_buffer =
+					&(instance->contg_buffers[i]);
+
+			if (contg_buffer->virt_user_addr != 0) {
+				free_continguous_pages(
+					contg_buffer->virt_kernel_addr,
+					contg_buffer->num_pages);
+			}
+		}
+
+		/* release instance context */
+		kfree(instance);
+	} while (FALSE);
+
+	return ret;
+}
+EXPORT_SYMBOL(mobicore_release);
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function will be called from user space as close(...).
+ * The instance data are freed and the associated memory pages are unreserved.
+ *
+ * @param inode
+ * @param file
+ *
+ * @return 0
+ */
+static int mc_kernel_module_release(
+	struct inode	*inode,
+	struct file	*file
+)
+{
+	int			ret = 0;
+	struct mc_instance	*instance = get_instance(file);
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	do {
+		/* check if daemon closes us. */
+		if (is_caller_mc_daemon(instance)) {
+			/* TODO: cleanup?
+				* mc_drv_kmod_ctx.mc_used_l2_tables remains */
+			MCDRV_DBG_WARN("WARNING: MobiCore Daemon died\n");
+			mc_drv_kmod_ctx.daemon_inst = NULL;
+		}
+
+		ret = mobicore_release(instance);
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function represents the interrupt function of the mcDrvModule.
+ * It signals by incrementing of an event counter and the start of the read
+ * waiting queue, the read function a interrupt has occurred.
+ *
+ * @param   intr
+ * @param   *context  pointer to registered device data
+ *
+ * @return  IRQ_HANDLED
+ */
+static irqreturn_t mc_kernel_module_intr_ssiq(
+	int	intr,
+	void	*context
+)
+{
+	irqreturn_t	ret = IRQ_NONE;
+
+	/* we know the context. */
+	MCDRV_ASSERT(&mc_drv_kmod_ctx == context);
+
+	do {
+		if (intr != MC_INTR_SSIQ) {
+			/* this should not happen, as we did no register for any
+				other interrupt. For debugging, we print a
+				message, but continue */
+			MCDRV_DBG_WARN(
+				"unknown interrupt %d, expecting only %d\n",
+				intr, MC_INTR_SSIQ);
+		}
+		MCDRV_DBG_VERBOSE("received interrupt %d\n",
+				  intr);
+
+		/* increment interrupt event counter */
+		atomic_inc(&(mc_drv_kmod_ctx.ssiq_ctx.counter));
+
+		/* signal the daemon */
+		up(&mc_drv_kmod_ctx.daemon_ctx.sem);
+
+
+		ret = IRQ_HANDLED;
+
+	} while (FALSE);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/** function table structure of this device driver. */
+static const struct file_operations mc_kernel_module_file_operations = {
+	.owner		= THIS_MODULE, /**< driver owner */
+	.open		= mc_kernel_module_open, /**< driver open function */
+	.release	= mc_kernel_module_release, /**< driver release function*/
+	.unlocked_ioctl	= mc_kernel_module_ioctl, /**< driver ioctl function */
+	.mmap		= mc_kernel_module_mmap, /**< driver mmap function */
+	.read		= mc_kernel_module_read, /**< driver read function */
+};
+
+/*----------------------------------------------------------------------------*/
+/** registration structure as miscdevice. */
+static struct miscdevice mc_kernel_module_device = {
+	.name	= MC_DRV_MOD_DEVNODE, /**< device name */
+	.minor	= MISC_DYNAMIC_MINOR, /**< device minor number */
+	/** device interface function structure */
+	.fops	= &mc_kernel_module_file_operations,
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function is called the kernel during startup or by a insmod command.
+ * This device is installed and registered as miscdevice, then interrupt and
+ * queue handling is set up
+ *
+ * @return 0 for no error or -EIO if registration fails
+ */
+static int __init mc_kernel_module_init(
+	void
+)
+{
+	int ret = 0;
+
+	MCDRV_DBG("enter (Build " __TIMESTAMP__ ")\n");
+	MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
+			MCDRVMODULEAPI_VERSION_MAJOR,
+			MCDRVMODULEAPI_VERSION_MINOR);
+#ifdef MOBICORE_COMPONENT_BUILD_TAG
+	MCDRV_DBG("%s\n", MOBICORE_COMPONENT_BUILD_TAG);
+#endif
+	do {
+		/* Hardware does not support ARM TrustZone
+			-> Cannot continue! */
+		if (!has_security_extensions()) {
+			MCDRV_DBG_ERROR(
+				"Hardware does't support ARM TrustZone!\n");
+			ret = -ENODEV;
+			break;
+		}
+
+		/* Running in secure mode -> Cannot load the driver! */
+		if (is_secure_mode()) {
+			MCDRV_DBG_ERROR("Running in secure MODE!\n");
+			ret = -ENODEV;
+			break;
+		}
+
+		sema_init(&mc_drv_kmod_ctx.daemon_ctx.sem, DAEMON_SEM_VAL);
+		/* set up S-SIQ interrupt handler */
+		ret = request_irq(
+				  MC_INTR_SSIQ,
+				  mc_kernel_module_intr_ssiq,
+				  IRQF_TRIGGER_RISING,
+				  MC_DRV_MOD_DEVNODE,
+				  &mc_drv_kmod_ctx);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("interrupt request failed\n");
+			break;
+		}
+
+		ret = misc_register(&mc_kernel_module_device);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("device register failed\n");
+			break;
+		}
+
+		/* initialize event counter for signaling of an IRQ to zero */
+		atomic_set(&(mc_drv_kmod_ctx.ssiq_ctx.counter), 0);
+
+		/* init list for WSM L2 chunks. */
+		INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_l2_tables_sets));
+
+		/* L2 table descriptor list. */
+		INIT_LIST_HEAD(&(mc_drv_kmod_ctx.mc_used_l2_tables));
+
+		sema_init(&(mc_drv_kmod_ctx.wsm_l2_sem), 1);
+
+		/* initialize unique number counter which we can use for
+			handles. It is limited to 2^32, but this should be
+			enough to be roll-over safe for us. We start with 1
+			instead of 0. */
+		atomic_set(&(mc_drv_kmod_ctx.unique_counter), 1);
+
+		mci_base = 0;
+		MCDRV_DBG("initialized\n");
+
+		ret = 0;
+
+	} while (FALSE);
+
+	MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+	return (int)ret;
+}
+
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * This function removes this device driver from the Linux device manager .
+ */
+static void __exit mc_kernel_module_exit(
+	void
+)
+{
+	struct mc_used_l2_table	*used_l2table;
+
+	MCDRV_DBG_VERBOSE("enter\n");
+
+	mobicore_log_free();
+
+	/* Check if some WSM is still in use. */
+	list_for_each_entry(
+		used_l2table,
+		&(mc_drv_kmod_ctx.mc_used_l2_tables),
+		list
+	) {
+		MCDRV_DBG_WARN(
+			"WSM L2 still in use: physBase=%p ,nr_of_pages=%d\n",
+			get_l2_table_phys(used_l2table),
+			used_l2table->nr_of_pages);
+	} /* end while */
+
+	free_irq(MC_INTR_SSIQ, &mc_drv_kmod_ctx);
+
+	misc_deregister(&mc_kernel_module_device);
+	MCDRV_DBG_VERBOSE("exit");
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* Linux Driver Module Macros */
+module_init(mc_kernel_module_init);
+module_exit(mc_kernel_module_exit);
+MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MobiCore driver");
+
+/** @} */
+
diff --git a/drivers/gud/mobicore_driver/mc_drv_module.h b/drivers/gud/mobicore_driver/mc_drv_module.h
new file mode 100644
index 0000000..8b402d6
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module.h
@@ -0,0 +1,238 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_DRV_KMOD_H_
+#define _MC_DRV_KMOD_H_
+
+#include "mc_drv_module_linux_api.h"
+#include "public/mc_drv_module_api.h"
+/** Platform specific settings */
+#include "platform.h"
+
+/** ARM Specific masks and modes */
+#define ARM_CPSR_MASK 0x1F
+#define ARM_MONITOR_MODE 0b10110
+#define ARM_SECURITY_EXTENSION_MASK 0x30
+
+/**
+ * Number of page table entries in one L2 table. This is ARM specific, an
+ *  L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
+ */
+#define MC_ARM_L2_TABLE_ENTRIES		256
+
+/** Maximum number of contiguous buffer allocations for one driver instance. */
+#define MC_DRV_KMOD_CONTG_BUFFER_MAX	16
+
+/** Number of pages for L2 tables. There are 4 table in each page. */
+#define MC_DRV_KMOD_L2_TABLE_PER_PAGES	4
+
+/** ARM level 2 (L2) table with 256 entries. Size: 1k */
+struct l2table {
+	pte_t	table_entries[MC_ARM_L2_TABLE_ENTRIES];
+};
+
+#define INVALID_ADDRESS     ((void *)(-1))
+
+/** ARM L2 PTE bits */
+#define L2_FLAG_SMALL_XN    (1U <<  0)
+#define L2_FLAG_SMALL       (1U <<  1)
+#define L2_FLAG_B           (1U <<  2)
+#define L2_FLAG_C           (1U <<  3)
+#define L2_FLAG_AP0         (1U <<  4)
+#define L2_FLAG_AP1         (1U <<  5)
+#define L2_FLAG_SMALL_TEX0  (1U <<  6)
+#define L2_FLAG_SMALL_TEX1  (1U <<  7)
+#define L2_FLAG_SMALL_TEX2  (1U <<  8)
+#define L2_FLAG_APX         (1U <<  9)
+#define L2_FLAG_S           (1U << 10)
+#define L2_FLAG_NG          (1U << 11)
+
+/**
+ * Contiguous buffer allocated to TLCs.
+ * These buffers are uses as world shared memory (wsm) and shared with
+ * secure world.
+ * The virtual kernel address is added for a simpler search algorithm.
+ */
+struct mc_contg_buffer {
+	unsigned int	handle; /* unique handle */
+	void		*virt_user_addr; /**< virtual User start address */
+	void		*virt_kernel_addr; /**< virtual Kernel start address */
+	void		*phys_addr; /**< physical start address */
+	unsigned int	num_pages; /**< number of pages */
+};
+
+/** Instance data for MobiCore Daemon and TLCs. */
+struct mc_instance {
+	/** unique handle */
+	unsigned int	handle;
+	/** process that opened this instance */
+	pid_t		pid_vnr;
+	/** buffer list for mmap generated address space and
+		its virtual client address */
+	struct mc_contg_buffer	contg_buffers[MC_DRV_KMOD_CONTG_BUFFER_MAX];
+};
+
+/** Store for four L2 tables in one 4kb page*/
+struct mc_l2_table_store {
+	struct l2table table[MC_DRV_KMOD_L2_TABLE_PER_PAGES];
+};
+
+/** Usage and maintenance information about mc_l2_table_store */
+struct mc_l2_tables_set {
+	struct list_head		list;
+	unsigned int			usage_bitmap;	/**< usage bitmap */
+	struct mc_l2_table_store	*kernel_virt;	/**< kernel virtual address */
+	struct mc_l2_table_store	*phys;		/**< physical address */
+	struct page			*page;		/**< pointer to page struct */
+};
+
+/**
+ * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
+ * When users map a malloc()ed area into SWd, a L2 table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the L2 table and a handle for this table is returned to the user.
+ */
+struct mc_used_l2_table {
+	struct list_head	list;
+
+	/** handle as communicated to user mode */
+	unsigned int		handle;
+	unsigned int		flags;
+
+	/** owner of this L2 table */
+	struct mc_instance	*owner;
+
+	/** set describing where our L2 table is stored */
+	struct mc_l2_tables_set	*set;
+
+	/** index into L2 table set */
+	unsigned int		idx;
+
+	/** size of buffer */
+	unsigned int		nr_of_pages;
+};
+
+#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_APP   (1U << 0)
+#define MC_WSM_L2_CONTAINER_WSM_LOCKED_BY_MC    (1U << 1)
+
+
+/** MobiCore S-SIQ interrupt context data. */
+struct mc_ssiq_ctx {
+	/** S-SIQ interrupt counter */
+	atomic_t	counter;
+};
+
+/** MobiCore Daemon context data. */
+struct mc_daemon_ctx {
+	/** event semaphore */
+	struct semaphore	sem;
+	struct fasync_struct	*async_queue;
+	/** event counter */
+	unsigned int		ssiq_counter;
+};
+
+/** MobiCore Driver Kernel Module context data. */
+struct mc_drv_kmod_ctx {
+
+	/** ever incrementing counter */
+	atomic_t		unique_counter;
+
+	/** S-SIQ interrupt context */
+	struct mc_ssiq_ctx	ssiq_ctx;
+
+	/** MobiCore Daemon context */
+	struct mc_daemon_ctx	daemon_ctx;
+
+	/** pointer to instance of daemon */
+	struct mc_instance	*daemon_inst;
+
+	/** Backing store for L2 tables */
+	struct list_head	mc_l2_tables_sets;
+
+	/** Bookkeeping for used L2 tables */
+	struct list_head	mc_used_l2_tables;
+
+	/** semaphore to synchronize access to above lists */
+	struct semaphore	wsm_l2_sem;
+};
+
+/** MobiCore internal trace buffer structure. */
+struct mc_trace_buf {
+	uint32_t version; /**< version of trace buffer */
+	uint32_t length; /**< length of allocated buffer(includes header) */
+	uint32_t write_pos; /**< last write position */
+	char  buff[1]; /**< start of the log buffer */
+};
+
+/*** MobiCore internal trace log setup. */
+void mobicore_log_read(void);
+long mobicore_log_setup(void *);
+void mobicore_log_free(void);
+
+#define MCDRV_DBG_ERROR(txt, ...) \
+	printk(KERN_ERR "mcDrvKMod [%d] %s() ### ERROR: " txt, \
+		task_pid_vnr(current), \
+		__func__, \
+		##__VA_ARGS__)
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION()    do {} while (0)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE          MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...)     DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(txt, ...) \
+	printk(KERN_INFO "mcDrvKMod [%d on CPU%d] %s(): " txt, \
+		task_pid_vnr(current), \
+		raw_smp_processor_id(), \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(txt, ...) \
+	printk(KERN_WARNING "mcDrvKMod [%d] %s() WARNING: " txt, \
+		task_pid_vnr(current), \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_ASSERT(cond) \
+	do { \
+		if (unlikely(!(cond))) { \
+			panic("mcDrvKMod Assertion failed: %s:%d\n", \
+				__FILE__, __LINE__); \
+		} \
+	} while (0)
+
+#else
+
+#define MCDRV_DBG_VERBOSE(...)	DUMMY_FUNCTION()
+#define MCDRV_DBG(...)		DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...)	DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...)	DUMMY_FUNCTION()
+
+#endif /* [not] defined(DEBUG) */
+
+
+#endif /* _MC_DRV_KMOD_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_android.h b/drivers/gud/mobicore_driver/mc_drv_module_android.h
new file mode 100644
index 0000000..319509f
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module_android.h
@@ -0,0 +1,37 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Android specific defines
+ * @file
+ *
+ * Android specific defines
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_DRV_MODULE_ANDROID_H_
+#define _MC_DRV_MODULE_ANDROID_H_
+
+/* Defines needed to identify the Daemon in Android systems
+ * For the full list see:
+ * platform_system_core/include/private/android_filesystem_config.h in the
+ * Android source tree
+ */
+/* traditional unix root user */
+#define AID_ROOT	0
+/* system server */
+#define AID_SYSTEM	1000
+/* access to misc storage */
+#define AID_MISC	9998
+#define AID_NOBODY	9999
+/* first app user */
+#define AID_APP		10000
+
+#endif /* _MC_DRV_MODULE_ANDROID_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h
new file mode 100644
index 0000000..d058043
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module_fastcalls.h
@@ -0,0 +1,227 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * MobiCore Fast Call interface
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_DRV_MODULE_FC_H_
+#define _MC_DRV_MODULE_FC_H_
+
+#include "mc_drv_module.h"
+
+/**
+ * MobiCore SMCs
+ */
+enum mc_smc_codes {
+	MC_SMC_N_YIELD  = 0x3, /**< Yield to switch from NWd to SWd. */
+	MC_SMC_N_SIQ    = 0x4  /**< SIQ to switch from NWd to SWd. */
+};
+
+/**
+ * MobiCore fast calls. See MCI documentation
+ */
+enum mc_fast_call_codes {
+	MC_FC_INIT      = -1,
+	MC_FC_INFO      = -2,
+	MC_FC_POWER     = -3,
+	MC_FC_DUMP      = -4,
+	MC_FC_NWD_TRACE = -31 /**< Mem trace setup fastcall */
+};
+
+/**
+ * return code for fast calls
+ */
+enum mc_fast_calls_result {
+	MC_FC_RET_OK                       = 0,
+	MC_FC_RET_ERR_INVALID              = 1,
+	MC_FC_RET_ERR_ALREADY_INITIALIZED  = 5
+};
+
+
+
+/*------------------------------------------------------------------------------
+	structure wrappers for specific fastcalls
+------------------------------------------------------------------------------*/
+
+/** generic fast call parameters */
+union fc_generic {
+	struct {
+		uint32_t cmd;
+		uint32_t param[3];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t param[2];
+	} as_out;
+};
+
+
+/** fast call init */
+union mc_fc_init {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t base;
+		uint32_t nq_info;
+		uint32_t mcp_info;
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t rfu[2];
+	} as_out;
+};
+
+
+/** fast call info parameters */
+union mc_fc_info {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t ext_info_id;
+		uint32_t rfu[2];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t state;
+		uint32_t ext_info;
+	} as_out;
+};
+
+
+/** fast call S-Yield parameters */
+union mc_fc_s_yield {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t rfu[3];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t rfu[2];
+	} as_out;
+};
+
+
+/** fast call N-SIQ parameters */
+union mc_fc_nsiq {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t rfu[3];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t rfu[2];
+	} as_out;
+};
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * fast call to MobiCore
+ *
+ * @param fc_generic pointer to fast call data
+ */
+static inline void mc_fastcall(
+	union fc_generic *fc_generic
+)
+{
+	MCDRV_ASSERT(fc_generic != NULL);
+	/* We only expect to make smc calls on CPU0 otherwise something wrong
+	 * will happen */
+	MCDRV_ASSERT(raw_smp_processor_id() == 0);
+	mb();
+#ifdef MC_SMC_FASTCALL
+	{
+		int ret = 0;
+		MCDRV_DBG("Going into SCM()");
+		ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic));
+		MCDRV_DBG("Coming from SCM, scm_call=%i, resp=%d/0x%x\n",
+			ret,
+			fc_generic->as_out.resp, fc_generic->as_out.resp);
+	}
+#else
+	{
+		/* SVC expect values in r0-r3 */
+		register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
+		register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
+		register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
+		register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
+
+		/* one of the famous preprocessor hacks to stingitize things.*/
+#define __STR2(x)   #x
+#define __STR(x)    __STR2(x)
+
+		/* compiler does not support certain instructions
+		"SMC": secure monitor call.*/
+#define ASM_ARM_SMC         0xE1600070
+		/*   "BPKT": debugging breakpoint. We keep this, as is comes
+				quite handy for debugging. */
+#define ASM_ARM_BPKT        0xE1200070
+#define ASM_THUMB_BPKT      0xBE00
+
+
+		__asm__ volatile (
+			".word " __STR(ASM_ARM_SMC) "\n"
+			: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
+		);
+
+		/* set response */
+		fc_generic->as_out.resp     = reg0;
+		fc_generic->as_out.ret      = reg1;
+		fc_generic->as_out.param[0] = reg2;
+		fc_generic->as_out.param[1] = reg3;
+	}
+#endif
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * convert fast call return code to linux driver module error code
+ *
+ */
+static inline int convert_fc_ret(
+	uint32_t sret
+)
+{
+	int         ret = -EFAULT;
+
+	switch (sret) {
+
+	case MC_FC_RET_OK:
+		ret = 0;
+		break;
+
+	case MC_FC_RET_ERR_INVALID:
+		ret = -EINVAL;
+		break;
+
+	case MC_FC_RET_ERR_ALREADY_INITIALIZED:
+		ret = -EBUSY;
+		break;
+
+	default:
+		break;
+	} /* end switch( sret ) */
+	return ret;
+}
+
+#endif /* _MC_DRV_MODULE_FC_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h b/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h
new file mode 100644
index 0000000..b2a99f1
--- /dev/null
+++ b/drivers/gud/mobicore_driver/mc_drv_module_linux_api.h
@@ -0,0 +1,187 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Wrapper for Linux API
+ * @file
+ *
+ * Some convenient wrappers for memory functions
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_DRV_MODULE_LINUX_API_H_
+#define _MC_DRV_MODULE_LINUX_API_H_
+
+#include <linux/version.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <asm/sizes.h>
+#include <asm/pgtable.h>
+#include <linux/semaphore.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+
+
+/* make some nice types */
+#if !defined(TRUE)
+#define TRUE (1 == 1)
+#endif
+
+#if !defined(FALSE)
+#define FALSE (1 != 1)
+#endif
+
+
+/* Linux GCC modifiers */
+#if !defined(__init)
+#warning "missing definition: __init"
+/* define a dummy */
+#define __init
+#endif
+
+
+#if !defined(__exit)
+#warning "missing definition: __exit"
+/* define a dummy */
+#define __exit
+#endif
+
+
+#if !defined(__must_check)
+#warning "missing definition: __must_check"
+/* define a dummy */
+#define __must_check
+#endif
+
+
+#if !defined(__user)
+#warning "missing definition: __user"
+/* define a dummy */
+#define __user
+#endif
+
+#define INVALID_ORDER       ((unsigned int)(-1))
+
+/*----------------------------------------------------------------------------*/
+/* get start address of the 4 KiB page where the given addres is located in. */
+static inline void *get_page_start(
+	void *addr
+)
+{
+	return (void *)(((unsigned long)(addr)) & PAGE_MASK);
+}
+
+/*----------------------------------------------------------------------------*/
+/* get offset into the 4 KiB page where the given addres is located in. */
+static inline unsigned int get_offset_in_page(
+	void *addr
+)
+{
+	return (unsigned int)(((unsigned long)(addr)) & (~PAGE_MASK));
+}
+
+/*----------------------------------------------------------------------------*/
+/* get number of pages for a given buffer. */
+static inline unsigned int get_nr_of_pages_for_buffer(
+	void		*addr_start, /* may be null */
+	unsigned int	len
+)
+{
+	/* calculate used number of pages. Example:
+	offset+size    newSize+PAGE_SIZE-1    nr_of_pages
+	   0              4095                   0
+	   1              4096                   1
+	  4095            8190                   1
+	  4096            8191                   1
+	  4097            8192                   2 */
+
+	return (get_offset_in_page(addr_start) + len + PAGE_SIZE-1) / PAGE_SIZE;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/**
+ * convert a given size to page order, which is equivalent to finding log_2(x).
+ * The maximum for order was 5 in Linux 2.0 corresponding to 32 pages.
+ * Later versions allow 9 corresponding to 512 pages, which is 2 MB on
+ * most platforms). Anyway, the bigger order is, the more likely it is
+ * that the allocation will fail.
+ * Size       0           1  4097  8193  12289  24577  28673   40961   61441
+ * Pages      -           1     2     3      4      7      8      15      16
+ * Order  INVALID_ORDER   0     1     1      2      2      3       3       4
+ *
+ * @param  size
+ * @return order
+ */
+static inline unsigned int size_to_order(
+	unsigned int size
+)
+{
+	unsigned int order = INVALID_ORDER;
+
+	if (size != 0) {
+		/* ARMv5 as a CLZ instruction which count the leading zeros of
+		the binary representation of a value. It return a value
+		between 0 and 32.
+		Value   0   1   2   3   4   5   6   7   8   9  10 ...
+		CLZ    32  31  30  30  29  29  29  29  28  28  28 ...
+
+		We have excluded Size==0 before, so this is safe. */
+		order = __builtin_clz(
+				get_nr_of_pages_for_buffer(NULL, size));
+
+		/* there is a size overflow in get_nr_of_pages_for_buffer when
+		 * the size is too large */
+		if (unlikely(order > 31))
+			return INVALID_ORDER;
+		order = 31 - order;
+
+		/* above algorithm rounds down: clz(5)=2 instead of 3 */
+		/* quick correction to fix it: */
+		if (((1<<order)*PAGE_SIZE) < size)
+			order++;
+	}
+	return order;
+}
+
+/* magic linux macro */
+#if !defined(list_for_each_entry)
+/* stop compiler */
+#error "missing macro: list_for_each_entry()"
+/* define a dummy */
+#define list_for_each_entry(a, b, c)    if (0)
+#endif
+
+/*----------------------------------------------------------------------------*/
+/* return the page frame number of an address */
+static inline unsigned int addr_to_pfn(
+	void *addr
+)
+{
+	/* there is no real API for this */
+	return ((unsigned int)(addr)) >> PAGE_SHIFT;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* return the address of a page frame number */
+static inline void *pfn_to_addr(
+	unsigned int pfn
+)
+{
+	/* there is no real API for this */
+	return (void *)(pfn << PAGE_SHIFT);
+}
+
+#endif /* _MC_DRV_MODULE_LINUX_API_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
new file mode 100644
index 0000000..7034cb0
--- /dev/null
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -0,0 +1,50 @@
+/**
+ * Header file of MobiCore Driver Kernel Module Platform
+ * specific structures
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_DRV_PLATFORM_H_
+#define _MC_DRV_PLATFORM_H_
+
+/** MobiCore Interrupt for Qualcomm */
+#define MC_INTR_SSIQ						218
+
+/** Use SMC for fastcalls */
+#define MC_SMC_FASTCALL
+
+
+/*--------------- Implementation -------------- */
+#include <mach/scm.h>
+/* from following file */
+#define SCM_SVC_MOBICORE		250
+#define SCM_CMD_MOBICORE		1
+
+extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
+			void *resp_buf, size_t resp_len);
+
+static inline int smc_fastcall(void *fc_generic, size_t size)
+{
+	return scm_call(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE,
+			   fc_generic, size,
+			   fc_generic, size);
+}
+
+/** Enable mobicore mem traces */
+#define MC_MEM_TRACES
+
+#endif /* _MC_DRV_PLATFORM_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/public/mc_drv_module_api.h b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h
new file mode 100644
index 0000000..59366f3
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/mc_drv_module_api.h
@@ -0,0 +1,311 @@
+/** @addtogroup MCD_MCDIMPL_KMOD_API Mobicore Driver Module API
+ * @ingroup  MCD_MCDIMPL_KMOD
+ * @{
+ * Interface to Mobicore Driver Kernel Module.
+ * @file
+ *
+ * <h2>Introduction</h2>
+ * The MobiCore Driver Kernel Module is a Linux device driver, which represents
+ * the command proxy on the lowest layer to the secure world (Swd). Additional
+ * services like memory allocation via mmap and generation of a L2 tables for
+ * given virtual memory are also supported. IRQ functionallity receives
+ * information from the SWd in the non secure world (NWd).
+ * As customary the driver is handled as linux device driver with "open",
+ * "close" and "ioctl" commands. Access to the driver is possible after the
+ * device "/dev/mobicore" has been opened.
+ * The MobiCore Driver Kernel Module must be installed via
+ * "insmod mcDrvModule.ko".
+ *
+ *
+ * <h2>Version history</h2>
+ * <table class="customtab">
+ * <tr><td width="100px"><b>Date</b></td><td width="80px"><b>Version</b></td>
+ * <td><b>Changes</b></td></tr>
+ * <tr><td>2010-05-25</td><td>0.1</td><td>Initial Release</td></tr>
+ * </table>
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_DRV_MODULEAPI_H_
+#define _MC_DRV_MODULEAPI_H_
+
+#include "version.h"
+
+#define MC_DRV_MOD_DEVNODE		   "mobicore"
+#define MC_DRV_MOD_DEVNODE_FULLPATH  "/dev/" MC_DRV_MOD_DEVNODE
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command.
+ * INIT request data to SWD
+ */
+union mc_ioctl_init_params {
+	struct {
+		/** base address of mci buffer 4KB align */
+		uint32_t  base;
+		/** notification buffer start/length [16:16] [start, length] */
+		uint32_t  nq_offset;
+		/** length of notification queue */
+		uint32_t  nq_length;
+		/** mcp buffer start/length [16:16] [start, length] */
+		uint32_t  mcp_offset;
+		/** length of mcp buffer */
+		uint32_t  mcp_length;
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command.
+ * INFO request data to the SWD
+ */
+union mc_ioctl_info_params {
+	struct {
+		uint32_t  ext_info_id; /**< extended info ID */
+	} in;
+	struct {
+		uint32_t  state; /**< state */
+		uint32_t  ext_info; /**< extended info */
+	} out;
+};
+
+/**
+ * Mmap allocates and maps contiguous memory into a process.
+ * We use the third parameter, void *offset, to distinguish between some cases
+ * offset = MC_DRV_KMOD_MMAP_WSM	usual operation, pages are registered in
+					device structure and freed later.
+ * offset = MC_DRV_KMOD_MMAP_MCI	get Instance of MCI, allocates or mmaps
+					the MCI to daemon
+ * offset = MC_DRV_KMOD_MMAP_PERSISTENTWSM	special operation, without
+						registration of pages
+ *
+ * In mmap(), the offset specifies which of several device I/O pages is
+ *  requested. Linux only transfers the page number, i.e. the upper 20 bits to
+ *  kernel module. Therefore we define our special offsets as multiples of page
+ *  size.
+ */
+enum mc_mmap_memtype {
+	MC_DRV_KMOD_MMAP_WSM		= 0,
+	MC_DRV_KMOD_MMAP_MCI		= 4096,
+	MC_DRV_KMOD_MMAP_PERSISTENTWSM	= 8192
+};
+
+struct mc_mmap_resp {
+	uint32_t  handle; /**< WSN handle */
+	uint32_t  phys_addr; /**< physical address of WSM (or NULL) */
+	bool	  is_reused; /**< if WSM memory was reused, or new allocated */
+};
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_FREE ioctl command.
+ */
+union mc_ioctl_free_params {
+	struct {
+		uint32_t  handle; /**< driver handle */
+		uint32_t  pid; /**< process id */
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 command.
+ *
+ * Allocates a physical L2 table and maps the buffer into this page.
+ * Returns the physical address of the L2 table.
+ * The page alignment will be created and the appropriated pSize and pOffsetL2
+ * will be modified to the used values.
+ */
+union mc_ioctl_app_reg_wsm_l2_params {
+	struct {
+		uint32_t  buffer; /**< base address of the virtual address  */
+		uint32_t  len; /**< size of the virtual address space */
+		uint32_t  pid; /**< process id */
+	} in;
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+		uint32_t  phys_wsm_l2_table; /* physical address of the L2 table */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2
+ * command.
+ */
+struct mc_ioctl_app_unreg_wsm_l2_params {
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+		uint32_t  pid; /**< process id */
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 command.
+ */
+struct mc_ioctl_daemon_lock_wsm_l2_params {
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+	} in;
+	struct {
+		uint32_t phys_wsm_l2_table;
+	} out;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2
+ * command.
+ */
+struct mc_ioctl_daemon_unlock_wsm_l2_params {
+	struct {
+		uint32_t  handle; /**< driver handle for locked memory */
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
+ */
+union mc_ioctl_fc_execute_params {
+	struct {
+		/**< base address of mobicore binary */
+		uint32_t  phys_start_addr;
+		/**< length of DDR area */
+		uint32_t  length;
+	} in;
+	struct {
+		/* nothing */
+	} out;
+};
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_GET_VERSION ioctl command.
+ */
+struct mc_ioctl_get_version_params {
+	struct {
+		uint32_t	kernel_module_version;
+	} out;
+};
+
+/* @defgroup Mobicore_Driver_Kernel_Module_Interface IOCTL */
+
+
+
+
+/* TODO: use IOCTL macros like _IOWR. See Documentation/ioctl/ioctl-number.txt,
+	Documentation/ioctl/ioctl-decoding.txt */
+/**
+ * defines for the ioctl mobicore driver module function call from user space.
+ */
+enum mc_kmod_ioctl {
+
+	/*
+	 * get detailed MobiCore Status
+	 */
+	MC_DRV_KMOD_IOCTL_DUMP_STATUS  = 200,
+
+	/*
+	 * initialize MobiCore
+	 */
+	MC_DRV_KMOD_IOCTL_FC_INIT  = 201,
+
+	/*
+	 * get MobiCore status
+	 */
+	MC_DRV_KMOD_IOCTL_FC_INFO  = 202,
+
+	/**
+	 * ioctl parameter to send the YIELD command to the SWD.
+	 * Only possible in Privileged Mode.
+	 * ioctl(fd, MC_DRV_MODULE_YIELD)
+	 */
+	MC_DRV_KMOD_IOCTL_FC_YIELD =  203,
+	/**
+	 * ioctl parameter to send the NSIQ signal to the SWD.
+	 * Only possible in Privileged Mode
+	 * ioctl(fd, MC_DRV_MODULE_NSIQ)
+	 */
+	MC_DRV_KMOD_IOCTL_FC_NSIQ   =  204,
+	/**
+	 * ioctl parameter to tzbsp to start Mobicore binary from DDR.
+	 * Only possible in Privileged Mode
+	 * ioctl(fd, MC_DRV_KMOD_IOCTL_FC_EXECUTE)
+	 */
+	MC_DRV_KMOD_IOCTL_FC_EXECUTE =  205,
+
+	/**
+	 * Free's memory which is formerly allocated by the driver's mmap
+	 * command. The parameter must be this mmaped address.
+	 * The internal instance data regarding to this address are deleted as
+	 * well as each according memory page and its appropriated reserved bit
+	 * is cleared (ClearPageReserved).
+	 * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address beeing of
+	 * type long address
+	 */
+	MC_DRV_KMOD_IOCTL_FREE = 218,
+
+	/**
+	 * Creates a L2 Table of the given base address and the size of the
+	 * data.
+	 * Parameter: mc_ioctl_app_reg_wsm_l2_params
+	 */
+	MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2 = 220,
+
+	/**
+	 * Frees the L2 table created by a MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2
+	 * ioctl.
+	 * Parameter: mc_ioctl_app_unreg_wsm_l2_params
+	 */
+	MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2 = 221,
+
+
+	/* TODO: comment this. */
+	MC_DRV_KMOD_IOCTL_DAEMON_LOCK_WSM_L2 = 222,
+	MC_DRV_KMOD_IOCTL_DAEMON_UNLOCK_WSM_L2 = 223,
+
+	/**
+	 * Return kernel driver version.
+	 * Parameter: mc_ioctl_get_version_params
+	 */
+	MC_DRV_KMOD_IOCTL_GET_VERSION = 224,
+};
+
+
+#endif /* _MC_DRV_MODULEAPI_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
new file mode 100644
index 0000000..fdfc618
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/mc_kernel_api.h
@@ -0,0 +1,100 @@
+/** @addtogroup MCD_MCDIMPL_KMOD_KAPI Mobicore Driver Module API inside Kernel.
+ * @ingroup  MCD_MCDIMPL_KMOD
+ * @{
+ * Interface to Mobicore Driver Kernel Module inside Kernel.
+ * @file
+ *
+ * Interface to be used by module MobiCoreKernelAPI.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MOBICORE_KERNELMODULE_API_H_
+#define _MOBICORE_KERNELMODULE_API_H_
+
+struct mc_instance;
+
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(
+	void
+);
+
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(
+	struct mc_instance	*instance
+);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle		handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_allocate_wsm(
+	struct mc_instance	*instance,
+	unsigned long		requested_size,
+	uint32_t		*handle,
+	void			**kernel_virt_addr,
+	void			**phys_addr
+);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle		handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free(
+	struct mc_instance	*instance,
+	uint32_t		handle
+);
+
+/**
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr		address of the buffer(NB it must be kernel virtual!)
+ * @param len		buffer length
+ * @param handle	pointer to handle
+ * @param phys_wsm_l2_table	pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_map_vmem(
+	struct mc_instance	*instance,
+	void			*addr,
+	uint32_t		len,
+	uint32_t		*handle,
+	void			**phys_wsm_l2_table
+);
+
+/**
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(
+	struct mc_instance	*instance,
+	uint32_t		handle
+);
+#endif /* _MOBICORE_KERNELMODULE_API_H_ */
+/** @} */
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/mobicore_driver/public/version.h
new file mode 100644
index 0000000..9b2dbca
--- /dev/null
+++ b/drivers/gud/mobicore_driver/public/version.h
@@ -0,0 +1,36 @@
+/** @addtogroup MCD_MCDIMPL_KMOD
+ * @{
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_DRV_VERSION_H_
+#define _MC_DRV_VERSION_H_
+
+#define MCDRVMODULEAPI_VERSION_MAJOR 0
+#define MCDRVMODULEAPI_VERSION_MINOR 1
+
+#endif /* _MC_DRV_VERSION_H_ */
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c
new file mode 100644
index 0000000..13826f2
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/clientlib.c
@@ -0,0 +1,1093 @@
+/**
+ * MobiCore KernelApi module
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+#include <linux/list.h>
+
+#include "public/mobicore_driver_api.h"
+#include "public/mobicore_driver_cmd.h"
+#include "device.h"
+#include "session.h"
+
+/* device list */
+LIST_HEAD(devices);
+
+/*----------------------------------------------------------------------------*/
+static struct mcore_device_t *resolve_device_id(
+	uint32_t device_id
+) {
+	struct mcore_device_t *tmp;
+	struct list_head *pos;
+
+	/* Get mcore_device_t for device_id */
+	list_for_each(pos, &devices) {
+		tmp = list_entry(pos, struct mcore_device_t, list);
+		if (tmp->device_id == device_id)
+			return tmp;
+	}
+	return NULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static void add_device(
+	struct mcore_device_t *device
+) {
+	list_add_tail(&(device->list), &devices);
+}
+
+
+/*----------------------------------------------------------------------------*/
+static bool remove_device(
+	uint32_t device_id
+) {
+	struct mcore_device_t *tmp;
+	struct list_head *pos, *q;
+
+	list_for_each_safe(pos, q, &devices) {
+		tmp = list_entry(pos, struct mcore_device_t, list);
+		if (tmp->device_id == device_id) {
+			list_del(pos);
+			mcore_device_cleanup(tmp);
+			return true;
+		}
+	}
+	return false;
+}
+
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_open_device(
+	uint32_t device_id
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+	struct connection *dev_con = NULL;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		struct mcore_device_t *device = resolve_device_id(device_id);
+		if (device != NULL) {
+			MCDRV_DBG_ERROR("Device %d already opened", device_id);
+			mc_result = MC_DRV_ERR_INVALID_OPERATION;
+			break;
+		}
+
+		/* Open new connection to device */
+		dev_con = connection_new();
+		if (!connection_connect(dev_con, MC_DAEMON_PID)) {
+			MCDRV_DBG_ERROR(
+				"Could not setup netlink connection to PID %u",
+				MC_DAEMON_PID);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/* Forward device open to the daemon and read result */
+		struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+			/* .command_id = */ MC_DRV_CMD_OPEN_DEVICE
+			},
+		/* .payload = */ {
+		/* .device_id = */ device_id
+			}
+		};
+
+		int len = connection_write_data(
+				dev_con,
+				&mc_drv_cmd_open_device,
+				sizeof(struct mc_drv_cmd_open_device_t));
+		if (len < 0) {
+			MCDRV_DBG_ERROR("CMD_OPEN_DEVICE writeCmd failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		struct mc_drv_response_header_t  rsp_header;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_DEVICE readRsp failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_OPEN_DEVICE failed, respId=%d",
+							rsp_header.response_id);
+			switch (rsp_header.response_id) {
+			case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
+				mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+				break;
+			case MC_DRV_INVALID_DEVICE_NAME:
+				mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+				break;
+			case MC_DRV_RSP_DEVICE_ALREADY_OPENED:
+			default:
+				mc_result = MC_DRV_ERR_INVALID_OPERATION;
+				break;
+			}
+			break;
+		}
+
+		/* there is no payload to read */
+
+		device = mcore_device_create(device_id, dev_con);
+		if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
+			mcore_device_cleanup(device);
+			MCDRV_DBG_ERROR("could not open device file: %s",
+				MC_DRV_MOD_DEVNODE_FULLPATH);
+			mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
+			break;
+		}
+
+		add_device(device);
+
+	} while (false);
+
+	if (mc_result != MC_DRV_OK)
+		connection_cleanup(dev_con);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_open_device);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_close_device(
+	uint32_t device_id
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+	do {
+		struct mcore_device_t *device = resolve_device_id(device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		/* Return if not all sessions have been closed */
+		if (mcore_device_has_sessions(device)) {
+			MCDRV_DBG_ERROR("cannot close with sessions pending");
+			mc_result = MC_DRV_ERR_SESSION_PENDING;
+			break;
+		}
+
+		struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_CLOSE_DEVICE
+			}
+		};
+		int len = connection_write_data(
+				dev_con,
+				&mc_drv_cmd_close_device,
+				sizeof(struct mc_drv_cmd_close_device_t));
+		/* ignore error, but log details */
+		if (len < 0) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE writeCmd failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+		}
+
+		struct mc_drv_response_header_t  rsp_header;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE readResp failed "
+				" ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE failed, respId=%d",
+							rsp_header.response_id);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		remove_device(device_id);
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_close_device);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_open_session(
+	struct mc_session_handle *session,
+	const struct mc_uuid_t	*uuid,
+	uint8_t			*tci,
+	uint32_t		len
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (uuid == NULL) {
+			MCDRV_DBG_ERROR("UUID is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (tci == NULL) {
+			MCDRV_DBG_ERROR("TCI is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (len > MC_MAX_TCI_LEN) {
+			MCDRV_DBG_ERROR("TCI length is longer than %d",
+				MC_MAX_TCI_LEN);
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Get the device associated with the given session */
+		struct mcore_device_t *device =
+				resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		/* Get the physical address of the given TCI */
+		struct wsm *wsm =
+			mcore_device_find_contiguous_wsm(device, tci);
+		if (wsm == NULL) {
+			MCDRV_DBG_ERROR("Could not resolve TCI phy address ");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		if (wsm->len < len) {
+			MCDRV_DBG_ERROR("length is more than allocated TCI");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Prepare open session command */
+		struct mc_drv_cmd_open_session_t cmdOpenSession = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_OPEN_SESSION
+			},
+			/* .payload = */ {
+				/* .device_id = */ session->device_id,
+				/* .uuid = */ *uuid,
+				/* .tci = */ (uint32_t)wsm->phys_addr,
+				/* .len = */ len
+			}
+		};
+
+		/* Transmit command data */
+
+		int len = connection_write_data(
+						dev_con,
+						&cmdOpenSession,
+						sizeof(cmdOpenSession));
+		if (len != sizeof(cmdOpenSession)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION writeData failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/* Read command response */
+
+		/* read header first */
+		struct mc_drv_response_header_t rsp_header;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION readResp failed "
+				" ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION failed, respId=%d",
+							rsp_header.response_id);
+			switch (rsp_header.response_id) {
+			case MC_DRV_RSP_TRUSTLET_NOT_FOUND:
+				mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
+				break;
+			case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
+			case MC_DRV_RSP_DEVICE_NOT_OPENED:
+			case MC_DRV_RSP_FAILED:
+			default:
+				mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+				break;
+			}
+			break;
+		}
+
+		/* read payload */
+		struct mc_drv_rsp_open_session_payload_t
+						rsp_open_session_payload;
+		len = connection_read_datablock(
+					dev_con,
+					&rsp_open_session_payload,
+					sizeof(rsp_open_session_payload));
+		if (len != sizeof(rsp_open_session_payload)) {
+			MCDRV_DBG_ERROR("CMD_OPEN_SESSION readPayload failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/* Register session with handle */
+		session->session_id = rsp_open_session_payload.session_id;
+
+		/* Set up second channel for notifications */
+		struct connection *session_connection = connection_new();
+		/*TODO: no real need to connect here? */
+		if (!connection_connect(session_connection, MC_DAEMON_PID)) {
+			MCDRV_DBG_ERROR(
+				"Could not setup netlink connection to PID %u",
+				MC_DAEMON_PID);
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		/*TODO CONTINOUE HERE !!!! FIX RW RETURN HANDLING!!!! */
+
+		/* Write command to use channel for notifications */
+		struct mc_drv_cmd_nqconnect_t cmd_nqconnect = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_NQ_CONNECT
+			},
+			/* .payload = */ {
+				/* .device_id =  */ session->device_id,
+				/* .session_id = */ session->session_id,
+				/* .device_session_id = */
+				rsp_open_session_payload.device_session_id,
+				/* .session_magic = */
+					rsp_open_session_payload.session_magic
+			}
+		};
+		connection_write_data(session_connection,
+			&cmd_nqconnect,
+			sizeof(cmd_nqconnect));
+
+		/* Read command response, header first */
+		len = connection_read_datablock(
+					session_connection,
+					&rsp_header,
+					sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_NQ_CONNECT readRsp failed "
+				"ret=%d", len);
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_NQ_CONNECT failed, respId=%d",
+					rsp_header.response_id);
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_NQ_FAILED;
+			break;
+		}
+
+		/* there is no payload. */
+
+		/* Session established, new session object must be created */
+		mcore_device_create_new_session(
+			device,
+			session->session_id,
+			session_connection);
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_open_session);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_close_session(
+	struct mc_session_handle *session
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct mcore_device_t  *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection  *dev_con = device->connection;
+
+		struct session  *nq_session =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nq_session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* Write close session command */
+		struct mc_drv_cmd_close_session_t cmd_close_session = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_CLOSE_SESSION
+			},
+			/* .payload = */ {
+				/* .session_id = */ session->session_id,
+			}
+		};
+		connection_write_data(
+			dev_con,
+			&cmd_close_session,
+			sizeof(cmd_close_session));
+
+		/* Read command response */
+		struct mc_drv_response_header_t rsp_header;
+		int len = connection_read_datablock(
+						dev_con,
+						&rsp_header,
+						sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_SESSION readRsp failed "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_CLOSE_SESSION failed, respId=%d",
+							rsp_header.response_id);
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		mcore_device_remove_session(device, session->session_id);
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_close_session);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_notify(
+	struct mc_session_handle   *session
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	do {
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct mcore_device_t *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		struct session  *nqsession =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nqsession == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		struct mc_drv_cmd_notify_t cmd_notify = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_NOTIFY
+			},
+			/* .payload = */ {
+				/* .session_id = */ session->session_id,
+			}
+		};
+
+		connection_write_data(
+			dev_con,
+			&cmd_notify,
+			sizeof(cmd_notify));
+
+		/* Daemon will not return a response */
+
+	} while (false);
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_notify);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_wait_notification(
+	struct mc_session_handle  *session,
+	int32_t			timeout
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	do {
+		if (session == NULL) {
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct mcore_device_t  *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		struct session  *nq_session =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nq_session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		struct connection *nqconnection =
+					nq_session->notification_connection;
+		uint32_t count = 0;
+
+		/* Read notification queue till it's empty */
+		for (;;) {
+			struct notification notification;
+			ssize_t num_read = connection_read_data(
+				nqconnection,
+				&notification,
+				sizeof(notification),
+				timeout);
+			/* Exit on timeout in first run. Later runs have
+			 * timeout set to 0.
+			 * -2 means, there is no more data. */
+			if (count == 0 && num_read == -2) {
+				MCDRV_DBG_ERROR("read timeout");
+				mc_result = MC_DRV_ERR_TIMEOUT;
+				break;
+			}
+			/* After first notification the queue will be
+			 * drained, Thus we set no timeout for the
+			 * following reads */
+			timeout = 0;
+
+			if (num_read != sizeof(struct notification)) {
+				if (count == 0) {
+					/* failure in first read, notify it */
+					mc_result = MC_DRV_ERR_NOTIFICATION;
+					MCDRV_DBG_ERROR(
+					"read notification failed, "
+					"%i bytes received", (int)num_read);
+					break;
+				} else {
+					/* Read of the n-th notification
+					   failed/timeout. We don't tell the
+					   caller, as we got valid notifications
+					   before. */
+					mc_result = MC_DRV_OK;
+					break;
+				}
+			}
+
+			count++;
+			MCDRV_DBG_VERBOSE("readNq count=%d, SessionID=%d, "
+				"Payload=%d", count,
+				notification.session_id, notification.payload);
+
+			if (notification.payload != 0) {
+				/* Session end point died -> store exit code */
+				session_set_error_info(nq_session,
+					notification.payload);
+
+				mc_result = MC_DRV_INFO_NOTIFICATION;
+				break;
+			}
+		} /* for(;;) */
+
+	} while (false);
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_wait_notification);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_malloc_wsm(
+	uint32_t	device_id,
+	uint32_t	align,
+	uint32_t	len,
+	uint8_t		**wsm,
+	uint32_t	wsm_flags
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		struct mcore_device_t *device = resolve_device_id(device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		if (wsm == NULL) {
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		struct wsm *wsm_stack =
+			mcore_device_allocate_contiguous_wsm(device, len);
+		if (wsm_stack == NULL) {
+			MCDRV_DBG_ERROR("Allocation of WSM failed");
+			mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+			break;
+		}
+
+		*wsm = (uint8_t *)wsm_stack->virt_addr;
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_malloc_wsm);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_free_wsm(
+	uint32_t	device_id,
+	uint8_t		*wsm
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+	struct mcore_device_t *device;
+
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+
+		/* Get the device associated wit the given session */
+		device = resolve_device_id(device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		/* find WSM object */
+		struct wsm *wsm_stack =
+			mcore_device_find_contiguous_wsm(device, wsm);
+		if (wsm_stack == NULL) {
+			MCDRV_DBG_ERROR("unknown address");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Free the given virtual address */
+		if (!mcore_device_free_contiguous_wsm(device, wsm_stack)) {
+			MCDRV_DBG_ERROR("Free of virtual address failed");
+			mc_result = MC_DRV_ERR_FREE_MEMORY_FAILED;
+			break;
+		}
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_free_wsm);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_map(
+	struct mc_session_handle	*session_handle,
+	void				*buf,
+	uint32_t			buf_len,
+	struct mc_bulk_map		*map_info
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session_handle == NULL) {
+			MCDRV_DBG_ERROR("session_handle is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (map_info == NULL) {
+			MCDRV_DBG_ERROR("map_info is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (buf == NULL) {
+			MCDRV_DBG_ERROR("buf is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Determine device the session belongs to */
+		struct mcore_device_t  *device = resolve_device_id(
+						session_handle->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection *dev_con = device->connection;
+
+		/* Get session */
+		struct session  *session =
+		mcore_device_resolve_session_id(device,
+						session_handle->session_id);
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* Register mapped bulk buffer to Kernel Module and keep mapped
+		   bulk buffer in mind */
+		struct bulk_buffer_descriptor *bulk_buf = session_add_bulk_buf(
+			session, buf, buf_len);
+		if (bulk_buf == NULL) {
+			MCDRV_DBG_ERROR("Error mapping bulk buffer");
+			mc_result = MC_DRV_ERR_BULK_MAPPING;
+			break;
+		}
+
+		/* Prepare map command */
+		struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem = {
+			/* C++ does not support C99 designated initializers */
+			/* .header = */ {
+				/* .command_id = */ MC_DRV_CMD_MAP_BULK_BUF
+			},
+			/* .payload = */ {
+				/* .session_id = */ session->session_id,
+				/* .phys_addr_l2; = */
+					(uint32_t)bulk_buf->phys_addr_wsm_l2,
+				/* .offset_payload = */
+					(uint32_t)(bulk_buf->virt_addr) & 0xFFF,
+				/* .len_bulk_mem = */ bulk_buf->len
+			}
+		};
+
+		/* Transmit map command to MobiCore device */
+		connection_write_data(
+			dev_con,
+			&mc_drv_cmd_map_bulk_mem,
+			sizeof(mc_drv_cmd_map_bulk_mem));
+
+		/* Read command response */
+		struct mc_drv_response_header_t rsp_header;
+		int len = connection_read_datablock(
+						dev_con,
+						&rsp_header,
+						sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF readRsp failed, "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF failed, respId=%d",
+							rsp_header.response_id);
+			/* REV We ignore Daemon Error code because client cannot
+			   handle it anyhow. */
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+
+			/* Unregister mapped bulk buffer from Kernel Module and
+			   remove mapped bulk buffer from session maintenance */
+			if (!session_remove_bulk_buf(session, buf)) {
+				/* Removing of bulk buffer not possible */
+				MCDRV_DBG_ERROR("Unregistering of bulk memory"
+					"from Kernel Module failed");
+			}
+			break;
+		}
+
+		struct mc_drv_rsp_map_bulk_mem_payload_t
+						rsp_map_bulk_mem_payload;
+		connection_read_datablock(
+			dev_con,
+			&rsp_map_bulk_mem_payload,
+			sizeof(rsp_map_bulk_mem_payload));
+
+		/* Set mapping info for Trustlet */
+		map_info->secure_virt_addr =
+			(void *)(rsp_map_bulk_mem_payload.secure_virtual_adr);
+		map_info->secure_virt_len = buf_len;
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_map);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_unmap(
+	struct mc_session_handle	*session_handle,
+	void				*buf,
+	struct mc_bulk_map		*map_info
+) {
+	enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	/* Enter critical section */
+
+	do {
+		if (session_handle == NULL) {
+			MCDRV_DBG_ERROR("session_handle is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (map_info == NULL) {
+			MCDRV_DBG_ERROR("map_info is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+		if (buf == NULL) {
+			MCDRV_DBG_ERROR("buf is null");
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Determine device the session belongs to */
+		struct mcore_device_t  *device =
+			resolve_device_id(session_handle->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+		struct connection  *dev_con = device->connection;
+
+		/* Get session */
+		struct session  *session =
+			mcore_device_resolve_session_id(device,
+						session_handle->session_id);
+		if (session == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* Prepare unmap command */
+		struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = {
+				/* .header = */ {
+					/* .command_id = */
+						MC_DRV_CMD_UNMAP_BULK_BUF
+				},
+				/* .payload = */ {
+					/* .session_id = */ session->session_id,
+					/* .secure_virtual_adr = */
+					(uint32_t)(map_info->secure_virt_addr),
+					/* .len_bulk_mem =
+						map_info->secure_virt_len*/
+				}
+			};
+
+		connection_write_data(
+			dev_con,
+			&cmd_unmap_bulk_mem,
+			sizeof(cmd_unmap_bulk_mem));
+
+		/* Read command response */
+		struct mc_drv_response_header_t rsp_header;
+		int len = connection_read_datablock(
+						dev_con,
+						&rsp_header,
+						sizeof(rsp_header));
+		if (len != sizeof(rsp_header)) {
+			MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF readRsp failed, "
+				"ret=%d", len);
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		if (rsp_header.response_id != MC_DRV_RSP_OK) {
+			MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF failed, respId=%d",
+							rsp_header.response_id);
+			/* REV We ignore Daemon Error code because client
+			   cannot handle it anyhow. */
+			mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+			break;
+		}
+
+		struct mc_drv_rsp_unmap_bulk_mem_payload_t
+						rsp_unmap_bulk_mem_payload;
+		connection_read_datablock(
+			dev_con,
+			&rsp_unmap_bulk_mem_payload,
+			sizeof(rsp_unmap_bulk_mem_payload));
+
+		/* REV axh: what about check the payload? */
+
+		/* Unregister mapped bulk buffer from Kernel Module and
+		 * remove mapped bulk buffer from session maintenance */
+		if (!session_remove_bulk_buf(session, buf)) {
+			/* Removing of bulk buffer not possible */
+			MCDRV_DBG_ERROR("Unregistering of bulk memory from "
+							"Kernel Module failed");
+			mc_result = MC_DRV_ERR_BULK_UNMAPPING;
+			break;
+		}
+
+		mc_result = MC_DRV_OK;
+
+	} while (false);
+
+	/* Exit critical section */
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_unmap);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_get_session_error_code(
+	struct mc_session_handle   *session,
+	int32_t			 *last_error
+) {
+	enum mc_result mc_result = MC_DRV_OK;
+
+	MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+	do {
+		if (session == NULL || last_error == NULL) {
+			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+			break;
+		}
+
+		/* Get device */
+		struct mcore_device_t *device =
+					resolve_device_id(session->device_id);
+		if (device == NULL) {
+			MCDRV_DBG_ERROR("Device not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+			break;
+		}
+
+		/* Get session */
+		struct session *nqsession =
+		 mcore_device_resolve_session_id(device, session->session_id);
+		if (nqsession == NULL) {
+			MCDRV_DBG_ERROR("Session not found");
+			mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+			break;
+		}
+
+		/* get session error code from session */
+		*last_error = session_get_last_err(nqsession);
+
+	} while (false);
+
+	return mc_result;
+}
+EXPORT_SYMBOL(mc_get_session_error_code);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_driver_ctrl(
+	enum mc_driver_ctrl  param,
+	uint8_t		 *data,
+	uint32_t		len
+) {
+	MCDRV_DBG_WARN("not implemented");
+	return MC_DRV_ERR_NOT_IMPLEMENTED;
+}
+EXPORT_SYMBOL(mc_driver_ctrl);
+
+/*----------------------------------------------------------------------------*/
+enum mc_result mc_manage(
+	uint32_t  device_id,
+	uint8_t   *data,
+	uint32_t  len
+) {
+	MCDRV_DBG_WARN("not implemented");
+	return MC_DRV_ERR_NOT_IMPLEMENTED;
+}
+EXPORT_SYMBOL(mc_manage);
+
diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/mobicore_kernelapi/common.h
new file mode 100644
index 0000000..2a73474
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/common.h
@@ -0,0 +1,97 @@
+/**
+ *
+ * Common data types
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "connection.h"
+#include "mcinq.h"
+
+void mcapi_insert_connection(
+	struct connection *connection
+);
+
+void mcapi_remove_connection(
+	uint32_t seq
+);
+
+unsigned int mcapi_unique_id(
+	void
+);
+
+
+#define MC_DAEMON_PID 0xFFFFFFFF
+#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore"
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION()	do {} while (0)
+
+#define MCDRV_ERROR(txt, ...) \
+	printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE		  MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...)	 DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(txt, ...) \
+	printk(KERN_INFO "mcKernelApi %s(): " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(txt, ...) \
+	printk(KERN_WARNING "mcKernelApi %s() WARNING: " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+#define MCDRV_DBG_ERROR(txt, ...) \
+	printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
+		__func__, \
+		##__VA_ARGS__)
+
+
+#define MCDRV_ASSERT(cond) \
+	do { \
+		if (unlikely(!(cond))) { \
+			panic("mcKernelApi Assertion failed: %s:%d\n", \
+				__FILE__, __LINE__); \
+		} \
+	} while (0)
+
+#elif defined(NDEBUG)
+
+#define MCDRV_DBG_VERBOSE(...)	DUMMY_FUNCTION()
+#define MCDRV_DBG(...)		DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...)	DUMMY_FUNCTION()
+#define MCDRV_DBG_ERROR(...)	DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...)	DUMMY_FUNCTION()
+
+#else
+#error "Define DEBUG or NDEBUG"
+#endif /* [not] defined(DEBUG_MCMODULE) */
+
+
+#define LOG_I MCDRV_DBG_VERBOSE
+#define LOG_W MCDRV_DBG_WARN
+#define LOG_E MCDRV_DBG_ERROR
+
+
+#define assert(expr) MCDRV_ASSERT(expr)
+
+#endif /* COMMON_H */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/mobicore_kernelapi/connection.c
new file mode 100644
index 0000000..9048ae8
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/connection.c
@@ -0,0 +1,229 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * Connection data.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/semaphore.h>
+#include <linux/time.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+
+#include "connection.h"
+#include "common.h"
+
+/* Define the initial state of the Data Available Semaphore */
+#define SEM_NO_DATA_AVAILABLE 0
+
+/*----------------------------------------------------------------------------*/
+struct connection *connection_new(
+	void
+) {
+	struct connection *conn = kzalloc(sizeof(struct connection),
+					GFP_KERNEL);
+	conn->sequence_magic = mcapi_unique_id();
+	mutex_init(&conn->data_lock);
+	/* No data available */
+	sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
+
+	mcapi_insert_connection(conn);
+	return conn;
+}
+
+/*----------------------------------------------------------------------------*/
+struct connection *connection_create(
+	int	 socket_descriptor,
+	pid_t   dest
+) {
+	struct connection *conn = connection_new();
+
+	conn->peer_pid = dest;
+	return conn;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void connection_cleanup(
+	struct connection *conn
+) {
+	if (!conn)
+		return;
+
+	kfree_skb(conn->skb);
+
+	mcapi_remove_connection(conn->sequence_magic);
+	kfree(conn);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool connection_connect(
+	struct connection *conn,
+	pid_t		dest
+) {
+	/* Nothing to connect */
+	conn->peer_pid = dest;
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_readDataMsg(
+	struct connection *conn,
+	void *buffer,
+	uint32_t len
+) {
+	size_t ret = -1;
+	MCDRV_DBG_VERBOSE("reading connection data %u, connection data left %u",
+			len, conn->data_len);
+	/* trying to read more than the left data */
+	if (len > conn->data_len) {
+		ret = conn->data_len;
+		memcpy(buffer, conn->data_start, conn->data_len);
+		conn->data_len = 0;
+	} else {
+		ret = len;
+		memcpy(buffer, conn->data_start, len);
+		conn->data_len -= len;
+		conn->data_start += len;
+	}
+
+	if (conn->data_len == 0)	{
+		conn->data_start = NULL;
+		kfree_skb(conn->skb);
+		conn->skb = NULL;
+	}
+	MCDRV_DBG_VERBOSE("read %u",  ret);
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_read_datablock(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len
+) {
+	return connection_read_data(conn, buffer, len, -1);
+}
+
+
+/*----------------------------------------------------------------------------*/
+size_t connection_read_data(
+	struct connection *conn,
+	void		*buffer,
+	uint32_t	len,
+	int32_t		timeout
+) {
+	size_t ret = 0;
+
+	MCDRV_ASSERT(buffer != NULL);
+	MCDRV_ASSERT(conn->socket_descriptor != NULL);
+
+	MCDRV_DBG_VERBOSE("read data len = %u for PID = %u",
+						len, conn->sequence_magic);
+	do {
+		/* Wait until data is available or timeout
+		   msecs_to_jiffies(-1) -> wait forever for the sem */
+		if (down_timeout(&(conn->data_available_sem),
+				  msecs_to_jiffies(timeout))) {
+			MCDRV_DBG_VERBOSE("Timeout reading the data sem");
+			ret = -2;
+			break;
+		}
+
+		if (mutex_lock_interruptible(&(conn->data_lock))) {
+			MCDRV_DBG_ERROR("interrupted reading the data sem");
+			ret = -1;
+			break;
+		}
+		/* Have data, use it */
+		if (conn->data_len > 0)
+			ret = connection_readDataMsg(conn, buffer, len);
+
+			mutex_unlock(&(conn->data_lock));
+
+		/* There is still some data left */
+		if (conn->data_len > 0)
+			up(&conn->data_available_sem);
+	} while (0);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_write_data(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len
+) {
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	int ret = 0;
+
+	MCDRV_DBG_VERBOSE("buffer length %u from pid %u\n",
+		  len,  conn->sequence_magic);
+	do {
+		skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL);
+		if (!skb) {
+			ret = -1;
+			break;
+		}
+
+		nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2,
+					  NLMSG_LENGTH(len), NLM_F_REQUEST);
+		if (!nlh) {
+			ret = -1;
+			break;
+		}
+		memcpy(NLMSG_DATA(nlh), buffer, len);
+
+		netlink_unicast(conn->socket_descriptor, skb,
+						conn->peer_pid, MSG_DONTWAIT);
+		ret = len;
+	} while (0);
+
+	if (!ret && skb != NULL)
+		kfree_skb(skb);
+
+	return ret;
+}
+
+int connection_process(
+	struct connection *conn,
+	struct sk_buff *skb
+)
+{
+	int ret = 0;
+	do {
+		if (mutex_lock_interruptible(&(conn->data_lock))) {
+			MCDRV_DBG_ERROR("Interrupted getting data semaphore!");
+			ret = -1;
+			break;
+		}
+
+		kfree_skb(conn->skb);
+
+		/* Get a reference to the incomming skb */
+		conn->skb = skb_get(skb);
+		if (conn->skb) {
+			conn->data_msg = nlmsg_hdr(conn->skb);
+			conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0);
+			conn->data_start = NLMSG_DATA(conn->data_msg);
+			up(&(conn->data_available_sem));
+		}
+		mutex_unlock(&(conn->data_lock));
+		ret = 0;
+	} while (0);
+	return ret;
+}
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/mobicore_kernelapi/connection.h
new file mode 100644
index 0000000..0b468e6
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/connection.h
@@ -0,0 +1,122 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * Connection data.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef CONNECTION_H_
+#define CONNECTION_H_
+
+#include <linux/semaphore.h>
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#define MAX_PAYLOAD_SIZE 128
+
+struct connection {
+	struct sock *socket_descriptor; /**< Netlink socket */
+	uint32_t sequence_magic; /**< Random? magic to match requests/answers */
+
+	struct nlmsghdr *data_msg;
+	uint32_t data_len; /**< How much connection data is left */
+	void *data_start; /**< Start pointer of remaining data */
+	struct sk_buff *skb;
+
+	struct mutex data_lock; /**< Data protection lock */
+	struct semaphore data_available_sem; /**< Data protection semaphore */
+
+	pid_t self_pid; /**< PID address used for local connection */
+	pid_t peer_pid; /**< Remote PID for connection */
+
+	struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct connection *connection_new(
+	void
+);
+
+struct connection *connection_create(
+	int		  socket_descriptor,
+	pid_t		dest
+);
+
+void connection_cleanup(
+	struct connection *conn
+);
+
+/**
+  * Connect to destination.
+  *
+  * @param Destination pointer.
+  * @return true on success.
+  */
+bool connection_connect(
+	struct connection *conn,
+	pid_t		dest
+);
+
+
+/**
+  * Read bytes from the connection.
+  *
+  * @param buffer	Pointer to destination buffer.
+  * @param len	   Number of bytes to read.
+  * @return Number of bytes read.
+  */
+size_t connection_read_datablock(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len
+);
+/**
+  * Read bytes from the connection.
+  *
+  * @param buffer	Pointer to destination buffer.
+  * @param len	   Number of bytes to read.
+  * @param timeout   Timeout in milliseconds
+  * @return Number of bytes read.
+  * @return -1 if select() failed (returned -1)
+  * @return -2 if no data available, i.e. timeout
+  */
+size_t connection_read_data(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	 len,
+	int32_t	  timeout
+);
+
+/**
+  * Write bytes to the connection.
+  *
+  * @param buffer	Pointer to source buffer.
+  * @param len		Number of bytes to read.
+  * @return Number of bytes written.
+  */
+size_t connection_write_data(
+	struct connection *conn,
+	void		 *buffer,
+	uint32_t	  len
+);
+
+/**
+ * Write bytes to the connection.
+ *
+ * @param buffer	Pointer to source buffer.
+ * @param len		Number of bytes to read.
+ * @return Number of bytes written.
+ */
+int connection_process(
+	struct connection *conn,
+	struct sk_buff *skb
+);
+
+#endif /* CONNECTION_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/mobicore_kernelapi/device.c
new file mode 100644
index 0000000..dbeee6a
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/device.c
@@ -0,0 +1,257 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ *
+ * Client library device management.
+ *
+ * Device and Trustlet Session management Funtions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#include <linux/list.h>
+#include <linux/slab.h>
+#include "mc_kernel_api.h"
+#include "public/mobicore_driver_api.h"
+
+#include "device.h"
+#include "common.h"
+
+/*----------------------------------------------------------------------------*/
+struct wsm *wsm_create(
+	void	*virt_addr,
+	uint32_t  len,
+	uint32_t  handle,
+	void	*phys_addr /*= NULL this may be unknown, so is can be omitted.*/
+	)
+{
+	struct wsm *wsm = kzalloc(sizeof(struct wsm), GFP_KERNEL);
+	wsm->virt_addr = virt_addr;
+	wsm->len = len;
+	wsm->handle = handle;
+	wsm->phys_addr = phys_addr;
+	return wsm;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct mcore_device_t *mcore_device_create(
+	uint32_t  device_id,
+	struct connection  *connection
+) {
+	struct mcore_device_t *dev =
+			kzalloc(sizeof(struct mcore_device_t), GFP_KERNEL);
+	dev->device_id = device_id;
+	dev->connection = connection;
+
+	INIT_LIST_HEAD(&dev->session_vector);
+	INIT_LIST_HEAD(&dev->wsm_l2_vector);
+
+	return dev;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void mcore_device_cleanup(
+	struct mcore_device_t *dev
+) {
+	struct session *tmp;
+	struct wsm *wsm;
+	struct list_head *pos, *q;
+
+	/* Delete all session objects. Usually this should not be needed
+	 * as closeDevice()requires that all sessions have been closed before.*/
+	list_for_each_safe(pos, q, &dev->session_vector) {
+		tmp = list_entry(pos, struct session, list);
+		list_del(pos);
+		session_cleanup(tmp);
+	}
+
+	/* Free all allocated WSM descriptors */
+	list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
+		wsm = list_entry(pos, struct wsm, list);
+		/* mcKMod_free(dev->instance, wsm->handle); */
+		list_del(pos);
+		kfree(wsm);
+	}
+	connection_cleanup(dev->connection);
+
+	mcore_device_close(dev);
+	kfree(dev);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_open(
+	struct mcore_device_t   *dev,
+	const char *deviceName
+) {
+	dev->instance = mobicore_open();
+	return (dev->instance != NULL);
+}
+
+
+/*----------------------------------------------------------------------------*/
+void mcore_device_close(
+	struct mcore_device_t *dev
+) {
+	mobicore_release(dev->instance);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_has_sessions(
+	struct mcore_device_t *dev
+) {
+	return !list_empty(&dev->session_vector);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_create_new_session(
+	struct mcore_device_t	*dev,
+	uint32_t		session_id,
+	struct connection	*connection
+) {
+	/* Check if session_id already exists */
+	if (mcore_device_resolve_session_id(dev, session_id)) {
+		MCDRV_DBG_ERROR(" session %u already exists", session_id);
+		return false;
+	}
+	struct session *session = session_create(session_id, dev->instance,
+						connection);
+	list_add_tail(&(session->list), &(dev->session_vector));
+	return true;
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_remove_session(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+) {
+	bool ret = false;
+	struct session *tmp;
+	struct list_head *pos, *q;
+
+	list_for_each_safe(pos, q, &dev->session_vector) {
+		tmp = list_entry(pos, struct session, list);
+		if (tmp->session_id == session_id) {
+			list_del(pos);
+			session_cleanup(tmp);
+			ret = true;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct session *mcore_device_resolve_session_id(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+) {
+	struct session  *ret = NULL;
+	struct session *tmp;
+	struct list_head *pos;
+
+
+	/* Get session for session_id */
+	list_for_each(pos, &dev->session_vector) {
+		tmp = list_entry(pos, struct session, list);
+		if (tmp->session_id == session_id) {
+			ret = tmp;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct wsm *mcore_device_allocate_contiguous_wsm(
+	struct mcore_device_t *dev,
+	uint32_t len
+) {
+	struct wsm *wsm = NULL;
+	do {
+		if (len == 0)
+			break;
+
+		/* Allocate shared memory */
+		void	*virt_addr;
+		uint32_t  handle;
+		void	*phys_addr;
+		int ret = mobicore_allocate_wsm(dev->instance,
+						len,
+						&handle,
+						&virt_addr,
+						&phys_addr);
+		if (ret != 0)
+			break;
+
+		/* Register (vaddr,paddr) with device */
+		wsm = wsm_create(virt_addr, len, handle, phys_addr);
+
+		list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
+
+	} while (0);
+
+	/* Return pointer to the allocated memory */
+	return wsm;
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_free_contiguous_wsm(
+	struct mcore_device_t  *dev,
+	struct wsm   *wsm
+) {
+	bool ret = false;
+	struct wsm *tmp;
+	struct list_head *pos;
+
+	list_for_each(pos, &dev->wsm_l2_vector) {
+		tmp = list_entry(pos, struct wsm, list);
+		if (tmp == wsm) {
+			ret = true;
+			break;
+		}
+	}
+
+	if (ret) {
+		MCDRV_DBG_VERBOSE("freeWsm virt_addr=0x%p, handle=%d",
+				wsm->virt_addr, wsm->handle);
+
+		/* ignore return code */
+		mobicore_free(dev->instance, wsm->handle);
+
+		list_del(pos);
+		kfree(wsm);
+	}
+	return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct wsm *mcore_device_find_contiguous_wsm(
+	struct mcore_device_t *dev,
+	void   *virt_addr
+) {
+	struct wsm *wsm;
+	struct list_head *pos;
+
+	list_for_each(pos, &dev->wsm_l2_vector) {
+		wsm = list_entry(pos, struct wsm, list);
+		if (virt_addr == wsm->virt_addr)
+			return wsm;
+	}
+
+	return NULL;
+}
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/mobicore_kernelapi/device.h
new file mode 100644
index 0000000..f40d993
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/device.h
@@ -0,0 +1,139 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ *
+ * Client library device management.
+ *
+ * Device and Trustlet Session management Functions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef DEVICE_H_
+#define DEVICE_H_
+
+#include <linux/list.h>
+
+#include "connection.h"
+#include "session.h"
+#include "wsm.h"
+
+
+struct mcore_device_t {
+	struct list_head session_vector; /**< MobiCore Trustlet session
+				associated with the device */
+	struct list_head	 wsm_l2_vector; /**< WSM L2 Table  */
+
+	uint32_t		device_id; /**< Device identifier */
+	struct connection	*connection; /**< The device connection */
+	struct mc_instance  *instance; /**< MobiCore Driver instance */
+
+	struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct mcore_device_t *mcore_device_create(
+	uint32_t	  device_id,
+	struct connection  *connection
+);
+
+void mcore_device_cleanup(
+	struct mcore_device_t *dev
+);
+
+/**
+  * Open the device.
+  * @param deviceName Name of the kernel modules device file.
+  * @return true if the device has been opened successfully
+  */
+bool mcore_device_open(
+	struct mcore_device_t   *dev,
+	const char *deviceName
+);
+
+/**
+  * Closes the device.
+  */
+void mcore_device_close(
+	struct mcore_device_t *dev
+);
+
+/**
+  * Check if the device has open sessions.
+  * @return true if the device has one or more open sessions.
+  */
+bool mcore_device_has_sessions(
+	struct mcore_device_t *dev
+);
+
+/**
+  * Add a session to the device.
+  * @param session_id session ID
+  * @param connection session connection
+  */
+bool mcore_device_create_new_session(
+	struct mcore_device_t	  *dev,
+	uint32_t	session_id,
+	struct connection  *connection
+);
+
+/**
+  * Remove the specified session from the device.
+  * The session object will be destroyed and all resources associated with it
+  * will be freed.
+  *
+  * @param session_id Session of the session to remove.
+  * @return true if a session has been found and removed.
+  */
+bool mcore_device_remove_session(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+);
+
+/**
+  * Get as session object for a given session ID.
+  * @param session_id Identified of a previously opened session.
+  * @return Session object if available or NULL if no session has been found.
+  */
+struct session *mcore_device_resolve_session_id(
+	struct mcore_device_t *dev,
+	uint32_t session_id
+);
+
+/**
+  * Allocate a block of contiguous WSM.
+  * @param len The virtual address to be registered.
+  * @return The virtual address of the allocated memory or NULL if no memory
+  * is available.
+  */
+struct wsm *mcore_device_allocate_contiguous_wsm(
+	struct mcore_device_t *dev,
+	uint32_t len
+);
+
+/**
+  * Unregister a vaddr from a device.
+  * @param vaddr The virtual address to be registered.
+  * @param paddr The physical address to be registered.
+  */
+bool mcore_device_free_contiguous_wsm(
+	struct mcore_device_t  *dev,
+	struct wsm *wsm
+);
+
+/**
+  * Get a WSM object for a given virtual address.
+  * @param vaddr The virtual address which has been allocate with mc_malloc_wsm()
+  * in advance.
+  * @return the WSM object or NULL if no address has been found.
+  */
+struct wsm *mcore_device_find_contiguous_wsm(
+	struct mcore_device_t *dev,
+	void   *virt_addr
+);
+
+#endif /* DEVICE_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/mobicore_kernelapi/include/mcinq.h
new file mode 100644
index 0000000..3cb82be
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/include/mcinq.h
@@ -0,0 +1,125 @@
+/** @addtogroup NQ
+ * @{
+ * Notifications inform the MobiCore runtime environment that information is
+ * pending in a WSM buffer.
+ * The Trustlet Connector (TLC) and the corresponding trustlet also utilize
+ * this buffer to notify each other about new data within the
+ * Trustlet Connector Interface (TCI).
+ *
+ * The buffer is set up as a queue, which means that more than one
+ * notification can be written to the buffer before the switch to the other
+ * world is performed. Each side therefore facilitates an incoming and an
+ * outgoing queue for communication with the other side.
+ *
+ * Notifications hold the session ID, which is used to reference the
+ * communication partner in the other world.
+ * So if, e.g., the TLC in the normal world wants to notify his trustlet
+ * about new data in the TLC buffer
+ *
+ * @file
+ * Notification queue declarations.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NQ_H_
+#define NQ_H_
+
+/** \name NQ Size Defines
+ * Minimum and maximum count of elements in the notification queue.
+ * @{ */
+#define MIN_NQ_ELEM 1   /**< Minimum notification queue elements. */
+#define MAX_NQ_ELEM 64 /**< Maximum notification queue elements. */
+/** @} */
+
+/** \name NQ Length Defines
+ * Minimum and maximum notification queue length.
+ * @{ */
+/**< Minimum notification length (in bytes). */
+#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification))
+/**< Maximum notification length (in bytes). */
+#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification))
+/** @} */
+
+/** \name Session ID Defines
+ * Standard Session IDs.
+ * @{ */
+/**< MCP session ID is used when directly communicating with the MobiCore
+ * (e.g. for starting and stopping of trustlets). */
+#define SID_MCP	   0
+/**< Invalid session id is returned in case of an error. */
+#define SID_INVALID   0xffffffff
+/** @} */
+
+/** Notification data structure. */
+struct notification {
+	uint32_t session_id; /**< Session ID. */
+	int32_t payload;	/**< Additional notification information. */
+};
+
+/** Notification payload codes.
+ * 0 indicated a plain simple notification,
+ * a positive value is a termination reason from the task,
+ * a negative value is a termination reason from MobiCore.
+ * Possible negative values are given below.
+ */
+enum notification_payload {
+	/**< task terminated, but exit code is invalid */
+	ERR_INVALID_EXIT_CODE   = -1,
+	/**< task terminated due to session end, no exit code available */
+	ERR_SESSION_CLOSE	   = -2,
+	/**< task terminated due to invalid operation */
+	ERR_INVALID_OPERATION   = -3,
+	/**< session ID is unknown */
+	ERR_INVALID_SID		 = -4,
+	/**<  session is not active */
+	ERR_SID_NOT_ACTIVE	  = -5
+};
+
+/** Declaration of the notification queue header.
+ * layout as specified in the data structure specification.
+ */
+struct notification_queue_header {
+	uint32_t write_cnt;  /**< Write counter. */
+	uint32_t read_cnt;   /**< Read counter. */
+	uint32_t queue_size; /**< Queue size. */
+};
+
+/** Queue struct which defines a queue object.
+ * The queue struct is accessed by the queue<operation> type of
+ * function. elementCnt must be a power of two and the power needs
+ * to be smaller than power of uint32_t (obviously 32).
+ */
+struct notification_queue {
+	/**< Queue header. */
+	struct notification_queue_header hdr;
+	/**< Notification elements. */
+	struct notification notification[MIN_NQ_ELEM];
+} ;
+
+#endif /** NQ_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/mobicore_kernelapi/include/mcuuid.h
new file mode 100644
index 0000000..b72acb8
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/include/mcuuid.h
@@ -0,0 +1,74 @@
+/**
+ * @addtogroup MC_UUID mcUuid - Universally Unique Identifier.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2011-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @ingroup  MC_DATA_TYPES
+ * @{
+ */
+
+#ifndef MC_UUID_H_
+#define MC_UUID_H_
+
+#define UUID_TYPE
+
+/** Universally Unique Identifier (UUID) according to ISO/IEC 11578. */
+struct mc_uuid_t {
+	uint8_t value[16]; /**< Value of the UUID. */
+};
+
+/** UUID value used as free marker in service provider containers. */
+#define MC_UUID_FREE_DEFINE \
+	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
+
+static const struct mc_uuid_t MC_UUID_FREE = {
+	MC_UUID_FREE_DEFINE
+};
+
+/** Reserved UUID. */
+#define MC_UUID_RESERVED_DEFINE \
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+static const struct mc_uuid_t MC_UUID_RESERVED = {
+	MC_UUID_RESERVED_DEFINE
+};
+
+/** UUID for system applications. */
+#define MC_UUID_SYSTEM_DEFINE \
+	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE }
+
+static const struct mc_uuid_t MC_UUID_SYSTEM = {
+	MC_UUID_SYSTEM_DEFINE
+};
+
+#endif /* MC_UUID_H_ */
+
+/** @} */
+
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c
new file mode 100644
index 0000000..62997f7
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/main.c
@@ -0,0 +1,181 @@
+/**
+ * MobiCore KernelApi module
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/netlink.h>
+#include <linux/kthread.h>
+#include <net/sock.h>
+
+#include <linux/list.h>
+
+#include "connection.h"
+#include "common.h"
+
+#define MC_DAEMON_NETLINK  17
+
+struct mc_kernelapi_ctx {
+	struct sock *sk;
+	struct list_head peers;
+	atomic_t counter;
+};
+
+struct mc_kernelapi_ctx *mod_ctx; /* = NULL; */
+
+/*----------------------------------------------------------------------------*/
+/* get a unique ID */
+unsigned int mcapi_unique_id(
+	void
+)
+{
+	return (unsigned int)atomic_inc_return(
+		&(mod_ctx->counter));
+}
+
+
+/*----------------------------------------------------------------------------*/
+static struct connection *mcapi_find_connection(
+	uint32_t seq
+)
+{
+	struct connection *tmp;
+	struct list_head *pos;
+
+	/* Get session for session_id */
+	list_for_each(pos, &mod_ctx->peers) {
+		tmp = list_entry(pos, struct connection, list);
+		if (tmp->sequence_magic == seq)
+			return tmp;
+	}
+
+	return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+void mcapi_insert_connection(
+	struct connection *connection
+)
+{
+	list_add_tail(&(connection->list), &(mod_ctx->peers));
+	connection->socket_descriptor = mod_ctx->sk;
+}
+
+void mcapi_remove_connection(
+	uint32_t seq
+)
+{
+	struct connection *tmp;
+	struct list_head *pos, *q;
+
+	/* Delete all session objects. Usually this should not be needed as
+	   closeDevice() requires that all sessions have been closed before.*/
+	list_for_each_safe(pos, q, &mod_ctx->peers) {
+		tmp = list_entry(pos, struct connection, list);
+		if (tmp->sequence_magic == seq) {
+			list_del(pos);
+			break;
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+static int mcapi_process(
+	struct sk_buff *skb,
+	struct nlmsghdr *nlh
+)
+{
+	struct connection *c;
+	int length;
+	int seq;
+	pid_t pid;
+	int ret;
+
+	pid = nlh->nlmsg_pid;
+	length = nlh->nlmsg_len;
+	seq = nlh->nlmsg_seq;
+	MCDRV_DBG_VERBOSE("nlmsg len %d type %d pid 0x%X seq %d\n",
+		   length, nlh->nlmsg_type, pid, seq);
+	do {
+		c = mcapi_find_connection(seq);
+		if (!c) {
+			MCDRV_ERROR("Invalid incomming connection - seq=%u!",
+				seq);
+			ret = -1;
+			break;
+		}
+
+		/* Pass the buffer to the appropriate connection */
+		connection_process(c, skb);
+
+		ret = 0;
+	} while (false);
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+static void mcapi_callback(
+	struct sk_buff *skb
+)
+{
+	struct nlmsghdr *nlh = nlmsg_hdr(skb);
+	int len = skb->len;
+	int err = 0;
+
+	while (NLMSG_OK(nlh, len)) {
+		err = mcapi_process(skb, nlh);
+
+		/* if err or if this message says it wants a response */
+		if (err || (nlh->nlmsg_flags & NLM_F_ACK))
+			netlink_ack(skb, nlh, err);
+
+		nlh = NLMSG_NEXT(nlh, len);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+static int __init mcapi_init(void)
+{
+	printk(KERN_INFO "Mobicore API module initialized!\n");
+
+	mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
+
+	/* start kernel thread */
+	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
+					mcapi_callback, NULL, THIS_MODULE);
+
+	if (!mod_ctx->sk) {
+		MCDRV_ERROR("register of recieve handler failed");
+		return -EFAULT;
+	}
+
+	INIT_LIST_HEAD(&mod_ctx->peers);
+	return 0;
+}
+
+static void __exit mcapi_exit(void)
+{
+	printk(KERN_INFO "Unloading Mobicore API module.\n");
+
+	if (mod_ctx->sk != NULL) {
+		netlink_kernel_release(mod_ctx->sk);
+		mod_ctx->sk = NULL;
+	}
+	kfree(mod_ctx);
+	mod_ctx = NULL;
+}
+
+module_init(mcapi_init);
+module_exit(mcapi_exit);
+
+MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MobiCore API driver");
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
new file mode 100644
index 0000000..ccfb2e5
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
@@ -0,0 +1,483 @@
+/**
+ * @defgroup MCD_API					MobiCore Driver API
+ * @addtogroup MCD_API
+ * @{
+ *
+ * @if DOXYGEN_MCDRV_API
+ *   @mainpage MobiCore Driver API.
+ * @endif
+ *
+ * MobiCore Driver API.
+ *
+ * The MobiCore (MC) Driver API provides access functions to the MobiCore
+ * runtime environment and the contained Trustlets.
+ *
+ * @image html DoxyOverviewDrvApi500x.png
+ * @image latex DoxyOverviewDrvApi500x.png "MobiCore Overview" width=12cm
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MCDRIVER_H_
+#define MCDRIVER_H_
+
+#define __MC_CLIENT_LIB_API
+
+#include "mcuuid.h"
+
+/**
+ * Return values of MobiCore driver functions.
+ */
+enum mc_result {
+	/**< Function call succeeded. */
+	MC_DRV_OK		= 0,
+	/**< No notification available. */
+	MC_DRV_NO_NOTIFICATION	= 1,
+	/**< Error during notification on communication level. */
+	MC_DRV_ERR_NOTIFICATION	= 2,
+	/**< Function not implemented. */
+	MC_DRV_ERR_NOT_IMPLEMENTED = 3,
+	/**< No more resources available. */
+	MC_DRV_ERR_OUT_OF_RESOURCES = 4,
+	/**< Driver initialization failed. */
+	MC_DRV_ERR_INIT = 5,
+	/**< Unknown error. */
+	MC_DRV_ERR_UNKNOWN	= 6,
+	/**< The specified device is unknown. */
+	MC_DRV_ERR_UNKNOWN_DEVICE = 7,
+	/**< The specified session is unknown.*/
+	MC_DRV_ERR_UNKNOWN_SESSION = 8,
+	/**< The specified operation is not allowed. */
+	MC_DRV_ERR_INVALID_OPERATION = 9,
+	/**< The response header from the MC is invalid. */
+	MC_DRV_ERR_INVALID_RESPONSE = 10,
+	/**< Function call timed out. */
+	MC_DRV_ERR_TIMEOUT = 11,
+	/**< Can not allocate additional memory. */
+	MC_DRV_ERR_NO_FREE_MEMORY = 12,
+	/**< Free memory failed. */
+	MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
+	/**< Still some open sessions pending. */
+	MC_DRV_ERR_SESSION_PENDING = 14,
+	/**< MC daemon not reachable */
+	MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
+	/**< The device file of the kernel module could not be opened. */
+	MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
+	/**< Invalid parameter. */
+	MC_DRV_ERR_INVALID_PARAMETER	= 17,
+	/**< Unspecified error from Kernel Module*/
+	MC_DRV_ERR_KERNEL_MODULE = 18,
+	/**< Error during mapping of additional bulk memory to session. */
+	MC_DRV_ERR_BULK_MAPPING = 19,
+	/**< Error during unmapping of additional bulk memory to session. */
+	MC_DRV_ERR_BULK_UNMAPPING = 20,
+	/**< Notification received, exit code available. */
+	MC_DRV_INFO_NOTIFICATION = 21,
+	/**< Set up of NWd connection failed. */
+	MC_DRV_ERR_NQ_FAILED = 22
+};
+
+
+/**
+ * Driver control command.
+ */
+enum mc_driver_ctrl {
+	MC_CTRL_GET_VERSION = 1 /**< Return the driver version */
+};
+
+
+/** Structure of Session Handle, includes the Session ID and the Device ID the
+ * Session belongs to.
+ * The session handle will be used for session-based MobiCore communication.
+ * It will be passed to calls which address a communication end point in the
+ * MobiCore environment.
+ */
+struct mc_session_handle {
+	uint32_t session_id; /**< MobiCore session ID */
+	uint32_t device_id; /**< Device ID the session belongs to */
+};
+
+/** Information structure about additional mapped Bulk buffer between the
+ * Trustlet Connector (Nwd) and the Trustlet (Swd). This structure is
+ * initialized from a Trustlet Connector by calling mc_map().
+ * In order to use the memory within a Trustlet the Trustlet Connector has to
+ * inform the Trustlet with the content of this structure via the TCI.
+ */
+struct mc_bulk_map {
+	/**< The virtual address of the Bulk buffer regarding the address space
+	 * of the Trustlet, already includes a possible offset! */
+	void *secure_virt_addr;
+	uint32_t secure_virt_len; /**< Length of the mapped Bulk buffer */
+};
+
+
+/**< The default device ID */
+#define MC_DEVICE_ID_DEFAULT	0
+/**< Wait infinite for a response of the MC. */
+#define MC_INFINITE_TIMEOUT	((int32_t)(-1))
+/**< Do not wait for a response of the MC. */
+#define MC_NO_TIMEOUT		0
+/**< TCI/DCI must not exceed 1MiB */
+#define MC_MAX_TCI_LEN		0x100000
+
+
+
+/** Open a new connection to a MobiCore device.
+ *
+ * mc_open_device() initializes all device specific resources required to
+ * communicate with an MobiCore instance located on the specified device in the
+ * system. If the device does not exist the function will return
+ * MC_DRV_ERR_UNKNOWN_DEVICE.
+ *
+ * @param [in] device_id Identifier for the MobiCore device to be used.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_ERR_INVALID_OPERATION if device already opened.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device_id is unknown.
+ * @return MC_DRV_ERR_INVALID_DEVICE_FILE if kernel module under
+ * /dev/mobicore cannot be opened
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_open_device(
+	uint32_t device_id
+);
+
+/** Close the connection to a MobiCore device.
+ * When closing a device, active sessions have to be closed beforehand.
+ * Resources associated with the device will be released.
+ * The device may be opened again after it has been closed.
+ *
+ * @param [in] device_id Identifier for the MobiCore device.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_SESSION_PENDING when a session is still open.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_close_device(
+	uint32_t device_id
+);
+
+/** Open a new session to a Trustlet. The trustlet with the given UUID has
+ * to be available in the flash filesystem.
+ *
+ * Write MCP open message to buffer and notify MobiCore about the availability
+ * of a new command.
+ * Waits till the MobiCore responses with the new session ID (stored in the MCP
+ * buffer).
+ *
+ * @param [in,out] session On success, the session data will be returned.
+ * Note that session.device_id has to be the device id of an opened device.
+ * @param [in] uuid UUID of the Trustlet to be opened.
+ * @param [in] tci TCI buffer for communicating with the trustlet.
+ * @param [in] tci_len Length of the TCI buffer. Maximum allowed value
+ * is MC_MAX_TCI_LEN.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon socket occur.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when daemon returns an error.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_open_session(
+	struct mc_session_handle  *session,
+	const struct mc_uuid_t *uuid,
+	uint8_t *tci,
+	uint32_t tci_len
+);
+
+/** Close a Trustlet session.
+ *
+ * Closes the specified MobiCore session. The call will block until the
+ * session has been closed.
+ *
+ * @pre Device device_id has to be opened in advance.
+ *
+ * @param [in] session Session to be closed.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_INVALID_DEVICE_FILE when daemon cannot open trustlet file.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_close_session(
+	struct mc_session_handle *session
+);
+
+/** Notify a session.
+ * Notifies the session end point about available message data.
+ * If the session parameter is correct, notify will always succeed.
+ * Corresponding errors can only be received by mc_wait_notification().
+ * @pre A session has to be opened in advance.
+ *
+ * @param session The session to be notified.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_notify(
+	struct mc_session_handle *session
+);
+
+/** Wait for a notification.
+ *
+ * Wait for a notification issued by the MobiCore for a specific session.
+ * The timeout parameter specifies the number of milliseconds the call will wait
+ * for a notification.
+ * If the caller passes 0 as timeout value the call will immediately return.
+ * If timeout value is below 0 the call will block until a notification for the
+ session has been received.
+ *
+ * @attention if timeout is below 0, call will block:
+ * Caller has to trust the other side to send a notification to wake him up
+ * again.
+ *
+ * @param [in] session The session the notification should correspond to.
+ * @param [in] timeout Time in milliseconds to wait
+ * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
+ * MC_INFINITE_TIMEOUT : wait infinitely)
+ *
+ * @return MC_DRV_OK if notification is available.
+ * @return MC_DRV_ERR_TIMEOUT if no notification arrived in time.
+ * @return MC_DRV_INFO_NOTIFICATION if a problem with the session was
+ * encountered. Get more details with mc_get_session_error_code().
+ * @return MC_DRV_ERR_NOTIFICATION if a problem with the socket occurred.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_wait_notification(
+	struct mc_session_handle  *session,
+	int32_t			timeout
+);
+
+/**
+ * Allocate a block of world shared memory (WSM).
+ * The MC driver allocates a contiguous block of memory which can be used as
+ * WSM.
+ * This implicates that the allocated memory is aligned according to the
+ * alignment parameter.
+ * Always returns a buffer of size WSM_SIZE aligned to 4K.
+ *
+ * @param [in]  device_id The ID of an opened device to retrieve the WSM from.
+ * @param [in]  align The alignment (number of pages) of the memory block
+ * (e.g. 0x00000001 for 4kb).
+ * @param [in]  len	Length of the block in bytes.
+ * @param [out] wsm Virtual address of the world shared memory block.
+ * @param [in]  wsm_flags Platform specific flags describing the memory to
+ * be allocated.
+ *
+ * @attention: align and wsm_flags are currently ignored
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_NO_FREE_MEMORY if no more contiguous memory is available
+ * in this size or for this process.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm(
+	uint32_t  device_id,
+	uint32_t  align,
+	uint32_t  len,
+	uint8_t   **wsm,
+	uint32_t  wsm_flags
+);
+
+/**
+ * Free a block of world shared memory (WSM).
+ * The MC driver will free a block of world shared memory (WSM) previously
+ * allocated with mc_malloc_wsm(). The caller has to assure that the address
+ * handed over to the driver is a valid WSM address.
+ *
+ * @param [in] device_id The ID to which the given address belongs.
+ * @param [in] wsm Address of WSM block to be freed.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_FREE_MEMORY_FAILED on failures.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(
+	uint32_t  device_id,
+	uint8_t   *wsm
+);
+
+/**
+ * Map additional bulk buffer between a Trustlet Connector (TLC) and
+ * the Trustlet (TL) for a session.
+ * Memory allocated in user space of the TLC can be mapped as additional
+ * communication channel (besides TCI) to the Trustlet. Limitation of the
+ * Trustlet memory structure apply: only 6 chunks can be mapped with a maximum
+ * chunk size of 1 MiB each.
+ *
+ * @attention It is up to the application layer (TLC) to inform the Trustlet
+ * about the additional mapped bulk memory.
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id. The
+ * given buffer is mapped to the session specified in the sessionHandle.
+ * @param [in] buf Virtual address of a memory portion (relative to TLC)
+ * to be shared with the Trustlet, already includes a possible offset!
+ * @param [in] len length of buffer block in bytes.
+ * @param [out] map_info Information structure about the mapped Bulk buffer
+ * between the TLC (Nwd) and
+ * the TL (Swd).
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_BULK_MAPPING when buf is already uses as bulk buffer or
+ * when registering the buffer failed.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_map(
+	struct mc_session_handle	*session,
+	void				*buf,
+	uint32_t			len,
+	struct mc_bulk_map		*map_info
+);
+
+/**
+ * Remove additional mapped bulk buffer between Trustlet Connector (TLC)
+ * and the Trustlet (TL) for a session.
+ *
+ * @attention The bulk buffer will immediately be unmapped from the session
+ * context.
+ * @attention The application layer (TLC) must inform the TL about unmapping
+ * of the additional bulk memory before calling mc_unmap!
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id. The given buffer is unmapped from the session specified
+ * in the sessionHandle.
+ * @param [in] buf Virtual address of a memory portion (relative to TLC)
+ * shared with the TL, already includes a possible offset!
+ * @param [in] map_info Information structure about the mapped Bulk buffer
+ * between the TLC (Nwd) and
+ * the TL (Swd).
+ * @attention The clientlib currently ignores the len field in map_info.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_BULK_UNMAPPING when buf was not registered earlier
+ * or when unregistering failed.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_unmap(
+	struct mc_session_handle	*session,
+	void				*buf,
+	struct mc_bulk_map		*map_info
+);
+
+
+/**
+ * @attention: Not implemented.
+ * Execute driver specific command.
+ * mc_driver_ctrl() can be used to execute driver specific commands.
+ * Besides the control command MC_CTRL_GET_VERSION commands are implementation
+ * specific.
+ * Please refer to the corresponding specification of the driver manufacturer.
+ *
+ * @param [in] param Command ID of the command to be executed.
+ * @param [in, out] data  Command data and response depending on command.
+ * @param [in] len Length of the data block.
+ *
+ * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_driver_ctrl(
+	enum mc_driver_ctrl  param,
+	uint8_t		 *data,
+	uint32_t	len
+);
+
+/**
+ * @attention: Not implemented.
+ * Execute application management command.
+ * mc_manage() shall be used to exchange application management commands with
+ * the MobiCore.
+ * The MobiCore Application Management Protocol is described in [MCAMP].
+ *
+ * @param [in] device_id Identifier for the MobiCore device to be used.
+ * NULL refers to the default device.
+ * @param [in, out] data  Command data/response data depending on command.
+ * @param [in] len Length of the data block.
+ *
+ * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_manage(
+	uint32_t  device_id,
+	uint8_t   *data,
+	uint32_t  len
+);
+
+/**
+ * Get additional error information of the last error that occured on a session.
+ * After the request the stored error code will be deleted.
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id.
+ * @param [out] last_error >0 Trustlet has terminated itself with this value,
+ * <0 Trustlet is dead because of an error within the MobiCore
+ * (e.g. Kernel exception).
+ * See also MCI definition.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code(
+	struct mc_session_handle  *session,
+	int32_t			*last_error
+);
+
+#endif /** MCDRIVER_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
new file mode 100644
index 0000000..9ff7989
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
@@ -0,0 +1,289 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON
+ * @{
+ * @file
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *	products derived from this software without specific prior
+ *	written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MCDAEMON_H_
+#define MCDAEMON_H_
+
+
+
+
+#include "mcuuid.h"
+
+enum mc_drv_cmd_t {
+	MC_DRV_CMD_PING			= 0,
+	MC_DRV_CMD_GET_INFO		= 1,
+	MC_DRV_CMD_OPEN_DEVICE		= 2,
+	MC_DRV_CMD_CLOSE_DEVICE		= 3,
+	MC_DRV_CMD_NQ_CONNECT		= 4,
+	MC_DRV_CMD_OPEN_SESSION		= 5,
+	MC_DRV_CMD_CLOSE_SESSION	= 6,
+	MC_DRV_CMD_NOTIFY		= 7,
+	MC_DRV_CMD_MAP_BULK_BUF		= 8,
+	MC_DRV_CMD_UNMAP_BULK_BUF	= 9
+};
+
+
+enum mc_drv_rsp_t {
+	MC_DRV_RSP_OK				= 0,
+	MC_DRV_RSP_FAILED			= 1,
+	MC_DRV_RSP_DEVICE_NOT_OPENED		= 2,
+	MC_DRV_RSP_DEVICE_ALREADY_OPENED	= 3,
+	MC_DRV_RSP_COMMAND_NOT_ALLOWED		= 4,
+	MC_DRV_INVALID_DEVICE_NAME		= 5,
+	MC_DRV_RSP_MAP_BULK_ERRO		= 6,
+	MC_DRV_RSP_TRUSTLET_NOT_FOUND		= 7,
+	MC_DRV_RSP_PAYLOAD_LENGTH_ERROR		= 8,
+};
+
+
+struct mc_drv_command_header_t {
+	uint32_t  command_id;
+};
+
+struct mc_drv_response_header_t {
+	uint32_t  response_id;
+};
+
+#define MC_DEVICE_ID_DEFAULT	0 /**< The default device ID */
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_open_device_payload_t {
+	uint32_t  device_id;
+};
+
+struct mc_drv_cmd_open_device_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_open_device_payload_t payload;
+};
+
+
+struct mc_drv_rsp_open_device_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_open_device_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_open_device_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_close_device_t {
+	struct mc_drv_command_header_t header;
+	/* no payload here because close has none.
+	   If we use an empty struct, C++ will count it as 4 bytes.
+	   This will write too much into the socket at write(cmd,sizeof(cmd)) */
+};
+
+
+struct mc_drv_rsp_close_device_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_close_device_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_close_device_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_open_session_payload_t {
+	uint32_t device_id;
+	struct mc_uuid_t uuid;
+	uint32_t tci;
+	uint32_t len;
+};
+
+struct mc_drv_cmd_open_session_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_open_session_payload_t payload;
+};
+
+
+struct mc_drv_rsp_open_session_payload_t {
+	uint32_t device_id;
+	uint32_t session_id;
+	uint32_t device_session_id;
+	uint32_t mc_result;
+	uint32_t session_magic;
+};
+
+struct mc_drv_rsp_open_session_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_open_session_payload_t  payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_close_session_payload_t {
+	uint32_t  session_id;
+};
+
+struct mc_drv_cmd_close_session_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_close_session_payload_t payload;
+};
+
+
+struct mc_drv_rsp_close_session_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_close_session_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_close_session_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_notify_payload_t {
+	uint32_t session_id;
+};
+
+struct mc_drv_cmd_notify_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_notify_payload_t payload;
+};
+
+
+struct mc_drv_rsp_notify_payload_t {
+	/* empty */
+};
+
+struct mc_drv_rsp_notify_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_notify_payload_t  payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_map_bulk_mem_payload_t {
+	uint32_t session_id;
+	uint32_t phys_addr_l2;
+	uint32_t offset_payload;
+	uint32_t len_bulk_mem;
+};
+
+struct mc_drv_cmd_map_bulk_mem_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_map_bulk_mem_payload_t  payload;
+};
+
+
+struct mc_drv_rsp_map_bulk_mem_payload_t {
+	uint32_t session_id;
+	uint32_t secure_virtual_adr;
+	uint32_t mc_result;
+};
+
+struct mc_drv_rsp_map_bulk_mem_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_map_bulk_mem_payload_t  payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_unmap_bulk_mem_payload_t {
+	uint32_t session_id;
+	uint32_t secure_virtual_adr;
+	uint32_t len_bulk_mem;
+};
+
+struct mc_drv_cmd_unmap_bulk_mem_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_unmap_bulk_mem_payload_t payload;
+};
+
+
+struct mc_drv_rsp_unmap_bulk_mem_payload_t {
+	uint32_t response_id;
+	uint32_t session_id;
+	uint32_t mc_result;
+};
+
+struct mc_drv_rsp_unmap_bulk_mem_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_unmap_bulk_mem_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_nqconnect_payload_t {
+	uint32_t device_id;
+	uint32_t session_id;
+	uint32_t device_session_id;
+	uint32_t session_magic; /* Random data */
+};
+
+struct mc_drv_cmd_nqconnect_t {
+	struct mc_drv_command_header_t header;
+	struct mc_drv_cmd_nqconnect_payload_t  payload;
+};
+
+
+struct mc_drv_rsp_nqconnect_payload_t {
+	/* empty; */
+};
+
+struct mc_drv_rsp_nqconnect_t {
+	struct mc_drv_response_header_t header;
+	struct mc_drv_rsp_nqconnect_payload_t payload;
+};
+
+
+/*****************************************************************************/
+union mc_drv_command_t {
+	struct mc_drv_command_header_t		header;
+	struct mc_drv_cmd_open_device_t		mc_drv_cmd_open_device;
+	struct mc_drv_cmd_close_device_t	mc_drv_cmd_close_device;
+	struct mc_drv_cmd_open_session_t	mc_drv_cmd_open_session;
+	struct mc_drv_cmd_close_session_t	mc_drv_cmd_close_session;
+	struct mc_drv_cmd_nqconnect_t		mc_drv_cmd_nqconnect;
+	struct mc_drv_cmd_notify_t		mc_drv_cmd_notify;
+	struct mc_drv_cmd_map_bulk_mem_t	mc_drv_cmd_map_bulk_mem;
+	struct mc_drv_cmd_unmap_bulk_mem_t	mc_drv_cmd_unmap_bulk_mem;
+};
+
+union mc_drv_response_t {
+	struct mc_drv_response_header_t		header;
+	struct mc_drv_rsp_open_device_t		mc_drv_rsp_open_device;
+	struct mc_drv_rsp_close_device_t	mc_drv_rsp_close_device;
+	struct mc_drv_rsp_open_session_t	mc_drv_rsp_open_session;
+	struct mc_drv_rsp_close_session_t	mc_drv_rsp_close_session;
+	struct mc_drv_rsp_nqconnect_t		mc_drv_rsp_nqconnect;
+	struct mc_drv_rsp_notify_t		mc_drv_rsp_notify;
+	struct mc_drv_rsp_map_bulk_mem_t	mc_drv_rsp_map_bulk_mem;
+	struct mc_drv_rsp_unmap_bulk_mem_t	mc_drv_rsp_unmap_bulk_mem;
+};
+
+#endif /* MCDAEMON_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/mobicore_kernelapi/session.c
new file mode 100644
index 0000000..e62b4b3
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/session.c
@@ -0,0 +1,202 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include "mc_kernel_api.h"
+#include "public/mobicore_driver_api.h"
+
+#include "session.h"
+
+/*****************************************************************************/
+struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
+	void		*virt_addr,
+	uint32_t	len,
+	uint32_t	handle,
+	void		*phys_addr_wsm_l2
+) {
+	struct bulk_buffer_descriptor *desc =
+		kzalloc(sizeof(struct bulk_buffer_descriptor), GFP_KERNEL);
+	desc->virt_addr = virt_addr;
+	desc->len = len;
+	desc->handle = handle;
+	desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
+	return desc;
+}
+
+/*****************************************************************************/
+struct session *session_create(
+	uint32_t	session_id,
+	void		*instance,
+	struct connection *connection
+) {
+	struct session *session =
+			kzalloc(sizeof(struct session), GFP_KERNEL);
+	session->session_id = session_id;
+	session->instance = instance;
+	session->notification_connection = connection;
+
+	session->session_info.last_error = SESSION_ERR_NO;
+	session->session_info.state = SESSION_STATE_INITIAL;
+
+	INIT_LIST_HEAD(&(session->bulk_buffer_descriptors));
+	return session;
+}
+
+
+/*****************************************************************************/
+void session_cleanup(
+	struct session *session
+) {
+	struct bulk_buffer_descriptor  *bulk_buf_descr;
+	struct list_head *pos, *q;
+
+	/* Unmap still mapped buffers */
+	list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+		bulk_buf_descr =
+			list_entry(pos, struct bulk_buffer_descriptor, list);
+
+		MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
+				"handle= %d",
+				(unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
+				bulk_buf_descr->handle);
+
+		/* ignore any error, as we cannot do anything in this case. */
+		int ret = mobicore_unmap_vmem(session->instance,
+						bulk_buf_descr->handle);
+		if (ret != 0)
+			MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+
+		list_del(pos);
+		kfree(bulk_buf_descr);
+	}
+
+	/* Finally delete notification connection */
+	connection_cleanup(session->notification_connection);
+	kfree(session);
+}
+
+
+/*****************************************************************************/
+void session_set_error_info(
+	struct session *session,
+	int32_t   err
+) {
+	session->session_info.last_error = err;
+}
+
+
+/*****************************************************************************/
+int32_t session_get_last_err(
+	struct session *session
+) {
+	return session->session_info.last_error;
+}
+
+
+/*****************************************************************************/
+struct bulk_buffer_descriptor *session_add_bulk_buf(
+	struct session	*session,
+	void		*buf,
+	uint32_t	len
+) {
+	struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
+	struct bulk_buffer_descriptor  *tmp;
+	struct list_head *pos;
+
+	/* Search bulk buffer descriptors for existing vAddr
+	   At the moment a virtual address can only be added one time */
+	list_for_each(pos, &session->bulk_buffer_descriptors) {
+		tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+		if (tmp->virt_addr == buf)
+			return NULL;
+	}
+
+	do {
+		/* Prepare the interface structure for memory registration in
+		   Kernel Module */
+		void	*l2_table_phys;
+		uint32_t  handle;
+
+		int ret = mobicore_map_vmem(session->instance,
+					buf,
+					len,
+					&handle,
+					&l2_table_phys);
+
+		if (ret != 0) {
+			MCDRV_DBG_ERROR("mobicore_map_vmem failed, ret=%d",
+					ret);
+			break;
+		}
+
+		MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
+				"handle=%d",
+				(unsigned int)l2_table_phys,
+				handle);
+
+		/* Create new descriptor */
+		bulk_buf_descr = bulk_buffer_descriptor_create(
+							buf,
+							len,
+							handle,
+							l2_table_phys);
+
+		/* Add to vector of descriptors */
+		list_add_tail(&(bulk_buf_descr->list),
+			&(session->bulk_buffer_descriptors));
+	} while (0);
+
+	return bulk_buf_descr;
+}
+
+
+/*****************************************************************************/
+bool session_remove_bulk_buf(
+	struct session *session,
+	void	*virt_addr
+) {
+	bool ret = true;
+	struct bulk_buffer_descriptor  *bulk_buf_descr = NULL;
+	struct bulk_buffer_descriptor  *tmp;
+	struct list_head *pos, *q;
+
+	MCDRV_DBG_VERBOSE("Virtual Address = 0x%X", (unsigned int) virt_addr);
+
+	/* Search and remove bulk buffer descriptor */
+	list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+		tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+		if (tmp->virt_addr == virt_addr) {
+			bulk_buf_descr = tmp;
+			list_del(pos);
+			break;
+		}
+	}
+
+	if (bulk_buf_descr == NULL) {
+		MCDRV_DBG_ERROR("Virtual Address not found");
+		ret = false;
+	} else {
+		MCDRV_DBG_VERBOSE("WsmL2 phys=0x%X, handle=%d",
+			(unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
+			bulk_buf_descr->handle);
+
+		/* ignore any error, as we cannot do anything */
+		int ret = mobicore_unmap_vmem(session->instance,
+						bulk_buf_descr->handle);
+		if (ret != 0)
+			MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+
+		kfree(bulk_buf_descr);
+	}
+
+	return ret;
+}
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/mobicore_kernelapi/session.h
new file mode 100644
index 0000000..9a53740
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/session.h
@@ -0,0 +1,136 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef SESSION_H_
+#define SESSION_H_
+
+#include "common.h"
+
+#include <linux/list.h>
+#include "connection.h"
+
+
+struct bulk_buffer_descriptor {
+	void		*virt_addr;/**< The virtual address of the Bulk buffer*/
+	uint32_t	len;	  /**< Length of the Bulk buffer*/
+	uint32_t	handle;
+	void		*phys_addr_wsm_l2; /**< The physical address of the
+				L2 table of the Bulk buffer*/
+	struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
+	void	*virt_addr,
+	uint32_t  len,
+	uint32_t  handle,
+	void	*phys_addr_wsm_l2
+);
+
+/** Session states.
+ * At the moment not used !!.
+ */
+enum session_state {
+	SESSION_STATE_INITIAL,
+	SESSION_STATE_OPEN,
+	SESSION_STATE_TRUSTLET_DEAD
+};
+
+#define SESSION_ERR_NO	  0 /**< No session error */
+
+/** Session information structure.
+ * The information structure is used to hold the state of the session, which
+ * will limit further actions for the session.
+ * Also the last error code will be stored till it's read.
+ */
+struct session_information {
+	enum session_state state;	   /**< Session state */
+	int32_t		last_error;	 /**< Last error of session */
+};
+
+
+struct session {
+	struct mc_instance		*instance;
+	/**< Descriptors of additional bulk buffer of a session */
+	struct list_head	bulk_buffer_descriptors;
+	/**< Informations about session */
+	struct session_information	 session_info;
+
+	uint32_t		 session_id;
+	struct connection	 *notification_connection;
+
+	/**< The list param for using the kernel lists*/
+	struct list_head list;
+};
+
+struct session *session_create(
+	uint32_t	 session_id,
+	void		 *instance,
+	struct connection *connection
+);
+
+void session_cleanup(
+	struct session *session
+);
+
+/**
+  * Add address information of additional bulk buffer memory to session and
+  * register virtual memory in kernel module.
+  *
+  * @attention The virtual address can only be added one time. If the virtual
+  * address already exist, NULL is returned.
+  *
+  * @param buf The virtual address of bulk buffer.
+  * @param len Length of bulk buffer.
+  *
+  * @return On success the actual Bulk buffer descriptor with all address
+  * information is retured, NULL if an error occurs.
+  */
+struct bulk_buffer_descriptor *session_add_bulk_buf(
+	struct session *session,
+	void	*buf,
+	uint32_t  len
+);
+
+/**
+  * Remove address information of additional bulk buffer memory from session and
+  * unregister virtual memory in kernel module
+  *
+  * @param buf The virtual address of the bulk buffer.
+  *
+  * @return true on success.
+  */
+bool session_remove_bulk_buf(
+	struct session *session,
+	void  *buf
+);
+
+/**
+  * Set additional error information of the last error that occured.
+  *
+  * @param errorCode The actual error.
+  */
+void session_set_error_info(
+	struct session *session,
+	int32_t err
+);
+
+/**
+  * Get additional error information of the last error that occured.
+  *
+  * @attention After request the information is set to SESSION_ERR_NO.
+  *
+  * @return Last stored error code or SESSION_ERR_NO.
+  */
+int32_t session_get_last_err(
+	struct session *session
+);
+
+#endif /* SESSION_H_ */
+
+/** @} */
diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/mobicore_kernelapi/wsm.h
new file mode 100644
index 0000000..6877c53
--- /dev/null
+++ b/drivers/gud/mobicore_kernelapi/wsm.h
@@ -0,0 +1,35 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * World shared memory definitions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef WSM_H_
+#define WSM_H_
+
+#include "common.h"
+#include <linux/list.h>
+
+struct wsm {
+	void *virt_addr;
+	uint32_t len;
+	uint32_t handle;
+	void *phys_addr;
+	struct list_head list;
+};
+
+struct wsm *wsm_create(
+	void	*virt_addr,
+	uint32_t  len,
+	uint32_t  handle,
+	void	*phys_addr /*= NULL this may be unknown, so is can be omitted.*/
+);
+#endif /* WSM_H_ */
+
+/** @} */
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index e1c87e3..e4935ae 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -65,6 +65,11 @@
 			(rq_data_dir(req) == WRITE))
 #define PACKED_CMD_VER		0x01
 #define PACKED_CMD_WR		0x02
+#define MMC_BLK_UPDATE_STOP_REASON(stats, reason)			\
+	do {								\
+		if (stats->enabled)					\
+			stats->pack_stop_reason[reason]++;		\
+	} while (0)
 
 static DEFINE_MUTEX(block_mutex);
 
@@ -1311,6 +1316,35 @@
 
 }
 
+struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(struct mmc_card *card)
+{
+	if (!card)
+		return NULL;
+
+	return &card->wr_pack_stats;
+}
+EXPORT_SYMBOL(mmc_blk_get_packed_statistics);
+
+void mmc_blk_init_packed_statistics(struct mmc_card *card)
+{
+	int max_num_of_packed_reqs = 0;
+
+	if (!card || !card->wr_pack_stats.packing_events)
+		return;
+
+	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+	spin_lock(&card->wr_pack_stats.lock);
+	memset(card->wr_pack_stats.packing_events, 0,
+		(max_num_of_packed_reqs + 1) *
+	       sizeof(*card->wr_pack_stats.packing_events));
+	memset(&card->wr_pack_stats.pack_stop_reason, 0,
+		sizeof(card->wr_pack_stats.pack_stop_reason));
+	card->wr_pack_stats.enabled = true;
+	spin_unlock(&card->wr_pack_stats.lock);
+}
+EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
+
 static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
 {
 	struct request_queue *q = mq->queue;
@@ -1323,6 +1357,7 @@
 	u8 put_back = 0;
 	u8 max_packed_rw = 0;
 	u8 reqs = 0;
+	struct mmc_wr_pack_stats *stats = &card->wr_pack_stats;
 
 	mmc_blk_clear_packed(mq->mqrq_cur);
 
@@ -1360,20 +1395,26 @@
 		phys_segments++;
 	}
 
+	spin_lock(&stats->lock);
+
 	while (reqs < max_packed_rw - 1) {
 		spin_lock_irq(q->queue_lock);
 		next = blk_fetch_request(q);
 		spin_unlock_irq(q->queue_lock);
-		if (!next)
+		if (!next) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, EMPTY_QUEUE);
 			break;
+		}
 
 		if (next->cmd_flags & REQ_DISCARD ||
 				next->cmd_flags & REQ_FLUSH) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, FLUSH_OR_DISCARD);
 			put_back = 1;
 			break;
 		}
 
 		if (rq_data_dir(cur) != rq_data_dir(next)) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, WRONG_DATA_DIR);
 			put_back = 1;
 			break;
 		}
@@ -1381,18 +1422,22 @@
 		if (mmc_req_rel_wr(next) &&
 				(md->flags & MMC_BLK_REL_WR) &&
 				!en_rel_wr) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, REL_WRITE);
 			put_back = 1;
 			break;
 		}
 
 		req_sectors += blk_rq_sectors(next);
 		if (req_sectors > max_blk_count) {
+			if (stats->enabled)
+				stats->pack_stop_reason[EXCEEDS_SECTORS]++;
 			put_back = 1;
 			break;
 		}
 
 		phys_segments +=  next->nr_phys_segments;
 		if (phys_segments > max_phys_segs) {
+			MMC_BLK_UPDATE_STOP_REASON(stats, EXCEEDS_SEGMENTS);
 			put_back = 1;
 			break;
 		}
@@ -1410,6 +1455,15 @@
 		spin_unlock_irq(q->queue_lock);
 	}
 
+	if (stats->enabled) {
+		if (reqs + 1 <= card->ext_csd.max_packed_writes)
+			stats->packing_events[reqs + 1]++;
+		if (reqs + 1 == max_packed_rw)
+			MMC_BLK_UPDATE_STOP_REASON(stats, THRESHOLD);
+	}
+
+	spin_unlock(&stats->lock);
+
 	if (reqs > 0) {
 		list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
 		mq->mqrq_cur->packed_num = ++reqs;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 84983e0..bca06a5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -246,6 +246,8 @@
 	card->dev.release = mmc_release_card;
 	card->dev.type = type;
 
+	spin_lock_init(&card->wr_pack_stats.lock);
+
 	return card;
 }
 
@@ -359,6 +361,8 @@
 		device_del(&card->dev);
 	}
 
+	kfree(card->wr_pack_stats.packing_events);
+
 	put_device(&card->dev);
 }
 
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index c1b0405..0efcf9d 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -287,6 +287,164 @@
 	.llseek		= default_llseek,
 };
 
+static int mmc_wr_pack_stats_open(struct inode *inode, struct file *filp)
+{
+	struct mmc_card *card = inode->i_private;
+
+	filp->private_data = card;
+	card->wr_pack_stats.print_in_read = 1;
+	return 0;
+}
+
+#define TEMP_BUF_SIZE 256
+static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf,
+				size_t cnt, loff_t *ppos)
+{
+	struct mmc_card *card = filp->private_data;
+	struct mmc_wr_pack_stats *pack_stats;
+	int i;
+	int max_num_of_packed_reqs = 0;
+	char *temp_buf;
+
+	if (!card)
+		return cnt;
+
+	if (!card->wr_pack_stats.print_in_read)
+		return 0;
+
+	if (!card->wr_pack_stats.enabled) {
+		pr_info("%s: write packing statistics are disabled\n",
+			 mmc_hostname(card->host));
+		goto exit;
+	}
+
+	pack_stats = &card->wr_pack_stats;
+
+	if (!pack_stats->packing_events) {
+		pr_info("%s: NULL packing_events\n", mmc_hostname(card->host));
+		goto exit;
+	}
+
+	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+	temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL);
+	if (!temp_buf)
+		goto exit;
+
+	spin_lock(&pack_stats->lock);
+
+	snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n",
+		mmc_hostname(card->host));
+	strlcat(ubuf, temp_buf, cnt);
+
+	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
+		if (pack_stats->packing_events[i]) {
+			snprintf(temp_buf, TEMP_BUF_SIZE,
+				 "%s: Packed %d reqs - %d times\n",
+				mmc_hostname(card->host), i,
+				pack_stats->packing_events[i]);
+			strlcat(ubuf, temp_buf, cnt);
+		}
+	}
+
+	snprintf(temp_buf, TEMP_BUF_SIZE,
+		 "%s: stopped packing due to the following reasons:\n",
+		 mmc_hostname(card->host));
+	strlcat(ubuf, temp_buf, cnt);
+
+	if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: exceed max num of segments\n",
+			 mmc_hostname(card->host),
+			 pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: exceed max num of sectors\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[EXCEEDS_SECTORS]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: wrong data direction\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[WRONG_DATA_DIR]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: flush or discard\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: empty queue\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[EMPTY_QUEUE]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[REL_WRITE]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: rel write\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[REL_WRITE]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+	if (pack_stats->pack_stop_reason[THRESHOLD]) {
+		snprintf(temp_buf, TEMP_BUF_SIZE,
+			 "%s: %d times: Threshold\n",
+			mmc_hostname(card->host),
+			pack_stats->pack_stop_reason[THRESHOLD]);
+		strlcat(ubuf, temp_buf, cnt);
+	}
+
+	spin_unlock(&pack_stats->lock);
+
+	kfree(temp_buf);
+
+	pr_info("%s", ubuf);
+
+exit:
+	if (card->wr_pack_stats.print_in_read == 1) {
+		card->wr_pack_stats.print_in_read = 0;
+		return strnlen(ubuf, cnt);
+	}
+
+	return 0;
+}
+
+static ssize_t mmc_wr_pack_stats_write(struct file *filp,
+				       const char __user *ubuf, size_t cnt,
+				       loff_t *ppos)
+{
+	struct mmc_card *card = filp->private_data;
+	int value;
+
+	if (!card)
+		return cnt;
+
+	sscanf(ubuf, "%d", &value);
+	if (value) {
+		mmc_blk_init_packed_statistics(card);
+	} else {
+		spin_lock(&card->wr_pack_stats.lock);
+		card->wr_pack_stats.enabled = false;
+		spin_unlock(&card->wr_pack_stats.lock);
+	}
+
+	return cnt;
+}
+
+static const struct file_operations mmc_dbg_wr_pack_stats_fops = {
+	.open		= mmc_wr_pack_stats_open,
+	.read		= mmc_wr_pack_stats_read,
+	.write		= mmc_wr_pack_stats_write,
+};
+
 void mmc_add_card_debugfs(struct mmc_card *card)
 {
 	struct mmc_host	*host = card->host;
@@ -319,6 +477,12 @@
 					&mmc_dbg_ext_csd_fops))
 			goto err;
 
+	if (mmc_card_mmc(card) && (card->ext_csd.rev >= 6) &&
+	    (card->host->caps2 & MMC_CAP2_PACKED_WR))
+		if (!debugfs_create_file("wr_pack_stats", S_IRUSR, root, card,
+					 &mmc_dbg_wr_pack_stats_fops))
+			goto err;
+
 	return;
 
 err:
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6178097..169fe68 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1223,6 +1223,24 @@
 		} else {
 			card->ext_csd.packed_event_en = 1;
 		}
+
+	}
+
+	if (!oldcard) {
+		if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
+		    (card->ext_csd.max_packed_writes > 0)) {
+			/*
+			 * We would like to keep the statistics in an index
+			 * that equals the num of packed requests
+			 * (1 to max_packed_writes)
+			 */
+			card->wr_pack_stats.packing_events = kzalloc(
+				(card->ext_csd.max_packed_writes + 1) *
+				sizeof(*card->wr_pack_stats.packing_events),
+				GFP_KERNEL);
+			if (!card->wr_pack_stats.packing_events)
+				goto free_card;
+		}
 	}
 
 	if (!oldcard)
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index d7edb82..cf98f68 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -649,6 +649,8 @@
 	u32 cfg_bits = 0xffffffff & ~(1 << 11);
 	u32 ver = 0;
 
+	SPS_DBG2("sps:%s:bam=0x%x(va).ee=%d.", __func__, (u32) base, ee);
+
 	ver = bam_read_reg_field(base, REVISION, BAM_REVISION);
 
 	if ((ver < BAM_MIN_VERSION) || (ver > BAM_MAX_VERSION)) {
@@ -743,6 +745,8 @@
 	u32 mask;
 	u32 pipe;
 
+	SPS_DBG2("sps:%s:bam=0x%x(va).", __func__, (u32) base);
+
 	/*
 	 * Discover the hardware version number and the number of pipes
 	 * supported by this BAM
@@ -782,6 +786,8 @@
 {
 	u32 ver = 0;
 
+	SPS_DBG2("sps:%s:bam=0x%x(va).", __func__, (u32) base);
+
 	if (!bam_read_reg_field(base, CTRL, BAM_EN)) {
 		SPS_ERR("sps:%s:bam 0x%x(va) is not enabled.\n",
 				__func__, (u32) base);
@@ -813,6 +819,8 @@
  */
 void bam_exit(void *base, u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).ee=%d.", __func__, (u32) base, ee);
+
 	bam_write_reg_field(base, IRQ_SRCS_MSK_EE(ee), BAM_IRQ, 0);
 
 	bam_write_reg(base, IRQ_EN, 0);
@@ -899,6 +907,8 @@
 int bam_pipe_init(void *base, u32 pipe,	struct bam_pipe_parameters *param,
 					u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	/* Reset the BAM pipe */
 	bam_write_reg(base, P_RST(pipe), 1);
 	/* No delay needed */
@@ -967,6 +977,8 @@
  */
 void bam_pipe_exit(void *base, u32 pipe, u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg(base, P_IRQ_EN(pipe), 0);
 
 	/* Disable the Pipe Interrupt at the BAM level */
@@ -982,6 +994,8 @@
  */
 void bam_pipe_enable(void *base, u32 pipe)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg_field(base, P_CTRL(pipe), P_EN, 1);
 }
 
@@ -991,6 +1005,8 @@
  */
 void bam_pipe_disable(void *base, u32 pipe)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg_field(base, P_CTRL(pipe), P_EN, 0);
 }
 
@@ -1010,6 +1026,8 @@
 void bam_pipe_set_irq(void *base, u32 pipe, enum bam_enable irq_en,
 		      u32 src_mask, u32 ee)
 {
+	SPS_DBG2("sps:%s:bam=0x%x(va).pipe=%d.", __func__, (u32) base, pipe);
+
 	bam_write_reg(base, P_IRQ_EN(pipe), src_mask);
 	bam_write_reg_field(base, IRQ_SRCS_MSK_EE(ee), (1 << pipe), irq_en);
 }
@@ -1287,7 +1305,7 @@
 		"BAM_P_IRQ_STTS: 0x%x\n"
 		"BAM_P_IRQ_STTS_P_TRNSFR_END_IRQ: 0x%x\n"
 		"BAM_P_IRQ_STTS_P_PRCSD_DESC_IRQ: 0x%x\n"
-		"BAM_P_IRQ_EN: %d\n"
+		"BAM_P_IRQ_EN: 0x%x\n"
 		"BAM_P_PRDCR_SDBNDn_BAM_P_BYTES_FREE: 0x%x (%d)\n"
 		"BAM_P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL: 0x%x (%d)\n"
 		"BAM_P_SW_DESC_OFST: 0x%x\n"
@@ -1335,4 +1353,50 @@
 		bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
 					P_EVNT_GEN_TRSHLD_P_TRSHLD));
 }
+
+/* output descriptor FIFO of a pipe */
+void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index)
+{
+	void *base = virt_addr;
+	u32 pipe = pipe_index;
+	u32 desc_fifo_addr;
+	u32 desc_fifo_size;
+	u32 *desc_fifo;
+	int i;
+
+	if (base == NULL)
+		return;
+
+	desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR(pipe));
+	desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES(pipe),
+						P_DESC_FIFO_SIZE);
+
+	if (desc_fifo_addr == 0) {
+		SPS_ERR("sps:%s:desc FIFO address of Pipe %d is NULL.\n",
+			__func__, pipe);
+		return;
+	} else if (desc_fifo_size == 0) {
+		SPS_ERR("sps:%s:desc FIFO size of Pipe %d is 0.\n",
+			__func__, pipe);
+		return;
+	}
+
+	SPS_INFO("\nsps:----- descriptor FIFO of Pipe %d -----\n", pipe);
+
+	SPS_INFO("BAM_P_DESC_FIFO_ADDR: 0x%x\n"
+		"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n",
+		desc_fifo_addr, desc_fifo_size, desc_fifo_size);
+
+	desc_fifo = (u32 *) phys_to_virt(desc_fifo_addr);
+
+	SPS_INFO("-------------------- begin of FIFO --------------------\n");
+
+	for (i = 0; i < desc_fifo_size; i += 0x10)
+		SPS_INFO("addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x.\n",
+			desc_fifo_addr + i,
+			desc_fifo[i / 4], desc_fifo[(i / 4) + 1],
+			desc_fifo[(i / 4) + 2], desc_fifo[(i / 4) + 3]);
+
+	SPS_INFO("--------------------  end of FIFO  --------------------\n");
+}
 #endif
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6d61bb6..fbaea09 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -327,6 +327,26 @@
 		print_bam_pipe_selected_reg(vir_addr, 4);
 		print_bam_pipe_selected_reg(vir_addr, 5);
 		break;
+	case 6: /* output desc FIFO of all active pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 7: /* output desc FIFO of some pipes */
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
+	case 8: /* output selected registers and valid desc FIFO of all pipes */
+		for (i = 0; i < num_pipes; i++) {
+			print_bam_pipe_selected_reg(vir_addr, i);
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		}
+		break;
+	case 9: /* output selected registers and desc FIFO of some pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
 	default:
 		pr_info("sps:no dump option is chosen yet.");
 	}
@@ -455,7 +475,7 @@
 	struct sps_bam_props bamdma_props = {0};
 #endif
 
-	SPS_DBG("sps:sps_device_init");
+	SPS_DBG2("sps:%s.", __func__);
 
 	success = false;
 
@@ -581,6 +601,8 @@
  */
 static int sps_client_init(struct sps_pipe *client)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if (client == NULL)
 		return -EINVAL;
 
@@ -609,6 +631,8 @@
  */
 static int sps_client_de_init(struct sps_pipe *client)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if (client->client_state != SPS_STATE_DISCONNECT) {
 		SPS_ERR("sps:De-init client in connected state: 0x%x",
 				   client->client_state);
@@ -637,6 +661,8 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	list_for_each_entry(bam, &sps->bams_q, list) {
 		if (bam->props.phys_addr == phys_addr)
 			return bam;
@@ -662,6 +688,8 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (handle == NULL) {
 		SPS_ERR("sps:%s:handle is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -697,6 +725,8 @@
 int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
 		  u32 addr, u32 size, int use_offset)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if ((mem_buffer == NULL) || (size == 0)) {
 		SPS_ERR("sps:invalid buffer address or size.");
 		return SPS_ERROR;
@@ -746,6 +776,8 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (h == SPS_DEV_HANDLE_MEM || h == SPS_DEV_HANDLE_INVALID)
 		return NULL;
 
@@ -821,6 +853,8 @@
 	struct sps_bam *bam;
 	int result;
 
+	SPS_DBG2("sps:%s.", __func__);
+
 	if (h == NULL) {
 		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -915,6 +949,8 @@
 	struct sps_bam *bam;
 	int result;
 
+	SPS_DBG2("sps:%s.", __func__);
+
 	if (pipe == NULL) {
 		SPS_ERR("sps:Invalid pipe.");
 		return SPS_ERROR;
@@ -1292,6 +1328,8 @@
 {
 	struct sps_pipe *pipe = h;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (h == NULL) {
 		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -1352,6 +1390,8 @@
 	struct sps_bam *bam;
 	int result;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (h == NULL) {
 		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -1401,6 +1441,8 @@
 int sps_alloc_mem(struct sps_pipe *h, enum sps_mem mem,
 		  struct sps_mem_buffer *mem_buffer)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if (h == NULL) {
 		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -1437,6 +1479,8 @@
  */
 int sps_free_mem(struct sps_pipe *h, struct sps_mem_buffer *mem_buffer)
 {
+	SPS_DBG("sps:%s.", __func__);
+
 	if (h == NULL) {
 		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -1500,6 +1544,8 @@
 	int ok;
 	int result;
 
+	SPS_DBG2("sps:%s.", __func__);
+
 	if (bam_props == NULL) {
 		SPS_ERR("sps:%s:bam_props is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -1647,6 +1693,8 @@
 {
 	struct sps_bam *bam;
 
+	SPS_DBG2("sps:%s.", __func__);
+
 	if (dev_handle == 0) {
 		SPS_ERR("sps:%s:device handle should not be 0.\n", __func__);
 		return SPS_ERROR;
@@ -1766,6 +1814,8 @@
 {
 	struct sps_pipe *ctx = NULL;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	ctx = kzalloc(sizeof(struct sps_pipe), GFP_KERNEL);
 	if (ctx == NULL) {
 		SPS_ERR("sps:Fail to allocate pipe context.");
@@ -1786,6 +1836,8 @@
 {
 	int res;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (ctx == NULL) {
 		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
 		return SPS_ERROR;
@@ -1808,6 +1860,8 @@
 	struct resource *resource;
 	struct msm_sps_platform_data *pdata;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	pdata = pdev->dev.platform_data;
 
 	if (pdata == NULL) {
@@ -1870,6 +1924,8 @@
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
 	struct resource *resource;
 
+	SPS_DBG("sps:%s.", __func__);
+
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-dma-res-pipes",
 				&sps->bamdma_restricted_pipes)) {
@@ -1920,7 +1976,7 @@
 {
 	int ret;
 
-	SPS_DBG("sps:msm_sps_probe.");
+	SPS_DBG2("sps:%s.", __func__);
 
 	if (pdev->dev.of_node) {
 		if (get_device_tree_data(pdev)) {
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index e0289ad..245ccd2 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -221,7 +221,7 @@
 				    IRQF_TRIGGER_HIGH, "sps", dev);
 
 		if (result) {
-			SPS_ERR("sps:Failed to register BAM 0x%x IRQ %d",
+			SPS_ERR("sps:Failed to enable BAM 0x%x IRQ %d",
 				BAM_ID(dev), dev->props.irq);
 			return SPS_ERROR;
 		}
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 8e4907b..e8ab832 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -193,6 +193,9 @@
 
 /* output the content of selected BAM pipe registers */
 void print_bam_pipe_selected_reg(void *, u32);
+
+/* output descriptor FIFO of a pipe */
+void print_bam_pipe_desc_fifo(void *, u32);
 #endif
 
 /**
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index e6dc795..a7161fe 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -48,12 +48,6 @@
 	OVERLAY_PERF_LEVEL4
 };
 
-enum mdp4_overlay_status {
-	MDP4_OVERLAY_TYPE_UNSET,
-	MDP4_OVERLAY_TYPE_SET,
-	MDP4_OVERLAY_TYPE_MAX
-};
-
 typedef int (*cmd_fxn_t)(struct platform_device *pdev);
 
 enum {		/* display */
@@ -727,8 +721,6 @@
 void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd);
 void mdp4_primary_vsync_dsi_video(void);
 uint32_t mdp4_ss_table_value(int8_t param, int8_t index);
-void mdp4_overlay_status_write(enum mdp4_overlay_status type, bool val);
-bool mdp4_overlay_status_read(enum mdp4_overlay_status type);
 void mdp4_overlay_ctrl_db_reset(void);
 
 int mdp4_overlay_writeback_on(struct platform_device *pdev);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index c46c683..6d4e44b 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -198,19 +198,6 @@
 	}
 }
 
-/* static array with index 0 for unset status and 1 for set status */
-static bool overlay_status[MDP4_OVERLAY_TYPE_MAX];
-
-void mdp4_overlay_status_write(enum mdp4_overlay_status type, bool val)
-{
-	overlay_status[type] = val;
-}
-
-bool mdp4_overlay_status_read(enum mdp4_overlay_status type)
-{
-	return overlay_status[type];
-}
-
 void mdp4_overlay_ctrl_db_reset(void)
 {
 	int i;
@@ -2517,12 +2504,6 @@
 
 	mdp4_stat.overlay_set[pipe->mixer_num]++;
 
-	if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
-		if (mdp_hw_revision == MDP4_REVISION_V2_1 &&
-			pipe->mixer_num == MDP4_MIXER0)
-			mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_SET, true);
-	}
-
 	if (ctrl->panel_mode & MDP4_PANEL_DTV &&
 	    pipe->mixer_num == MDP4_MIXER1) {
 		u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
@@ -2640,9 +2621,6 @@
 			}
 #else
 			if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
-				if (mdp_hw_revision == MDP4_REVISION_V2_1)
-					mdp4_overlay_status_write(
-						MDP4_OVERLAY_TYPE_UNSET, true);
 				if (mfd->panel_power_on)
 					mdp4_mddi_overlay_restore();
 			}
@@ -2749,7 +2727,7 @@
 	if (mfd->use_ov1_blt)
 		mdp4_overlay1_update_blt_mode(mfd);
 
-	mdp4_overlay_dtv_wait_for_ov(mfd, pipe);
+	mdp4_overlay_dtv_wait4vsync();
 	mdp4_iommu_unmap(pipe);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 83959df..5aa5965 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -450,27 +450,6 @@
 	/* change mdp clk while mdp is idle` */
 	mdp4_set_perf_level();
 
-	if (mdp_hw_revision == MDP4_REVISION_V2_1) {
-		if (mdp4_overlay_status_read(MDP4_OVERLAY_TYPE_UNSET)) {
-			uint32  data;
-			data = inpdw(MDP_BASE + 0x0028);
-			data &= ~0x0300;        /* bit 8, 9, MASTER4 */
-			if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */
-				data |= 0x0200;
-			else
-				data |= 0x0100;
-			MDP_OUTP(MDP_BASE + 0x00028, data);
-			mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_UNSET,
-				false);
-		}
-		if (mdp4_overlay_status_read(MDP4_OVERLAY_TYPE_SET)) {
-			uint32  data;
-			data = inpdw(MDP_BASE + 0x0028);
-			data &= ~0x0300;        /* bit 8, 9, MASTER4 */
-			MDP_OUTP(MDP_BASE + 0x00028, data);
-			mdp4_overlay_status_write(MDP4_OVERLAY_TYPE_SET, false);
-		}
-	}
 	mdp_enable_irq(MDP_OVERLAY0_TERM);
 	mfd->dma->busy = TRUE;
 	/* start OVERLAY pipe */
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 64baf2f..f1a2ada 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -98,11 +98,14 @@
 		pipe = writeback_pipe;
 	}
 	ret = panel_next_on(pdev);
+
 	/* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */
-	data = inpdw(MDP_BASE + 0x100F4);
-	data &= ~0x02; /* clear the mixer1 mux bit */
-	data |= 0x02;
+	if (hdmi_prim_display)
+		data = 0x01;
+	else
+		data = 0x02;
 	outpdw(MDP_BASE + 0x100F4, data);
+
 	MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004,
 		((0x0 & 0xFFF) << 16) | /* 12-bit B */
 			(0x0 & 0xFFF));         /* 12-bit G */
@@ -117,7 +120,6 @@
 int mdp4_overlay_writeback_off(struct platform_device *pdev)
 {
 	int ret;
-	uint32 data;
 	struct msm_fb_data_type *mfd =
 			(struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	if (mfd && writeback_pipe) {
@@ -129,11 +131,8 @@
 	}
 	ret = panel_next_off(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	/* MDP_LAYERMIXER_WB_MUX_SEL to restore
-	 * mixer1 axi for mixer1 writeback */
-	data = inpdw(MDP_BASE + 0x100F4);
-	data &= ~0x02; /* clear the mixer1 mux bit */
-	outpdw(MDP_BASE + 0x100F4, data);
+	/* MDP_LAYERMIXER_WB_MUX_SEL to restore to default cfg*/
+	outpdw(MDP_BASE + 0x100F4, 0x0);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return ret;
 }
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 0f43576..450fa85 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -289,6 +289,9 @@
 	case MIPI_CMD_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
 		break;
+	case WRITEBACK_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
+		break;
 	default:
 		ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
 		break;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index b480b42..64d2976 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -1064,20 +1064,10 @@
 
 void ddl_set_vidc_timeout(struct ddl_client_context *ddl)
 {
-	unsigned long core_clk_rate;
 	u32 vidc_time_out = 0;
-	if (ddl->codec_data.decoder.idr_only_decoding) {
+	if (ddl->codec_data.decoder.idr_only_decoding)
 		vidc_time_out = 2 * DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE;
-	} else {
-		res_trk_get_clk_rate(&core_clk_rate);
-		if (core_clk_rate == DDL_VIDC_1080P_48MHZ)
-			vidc_time_out = DDL_VIDC_1080P_48MHZ_TIMEOUT_VALUE;
-		else if (core_clk_rate == DDL_VIDC_1080P_133MHZ)
-			vidc_time_out = DDL_VIDC_1080P_133MHZ_TIMEOUT_VALUE;
-		else
-			vidc_time_out = DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE;
-	}
-	DDL_MSG_HIGH("%s Video core time out value = 0x%x"
+	DDL_MSG_HIGH("%s Video core time out value = 0x%x",
 		 __func__, vidc_time_out);
 	vidc_sm_set_video_core_timeout_value(
 		&ddl->shared_mem[ddl->command_channel], vidc_time_out);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c05134c..beb5470 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -176,6 +176,25 @@
 
 #define SDIO_MAX_FUNCS		7
 
+enum mmc_packed_stop_reasons {
+	EXCEEDS_SEGMENTS = 0,
+	EXCEEDS_SECTORS,
+	WRONG_DATA_DIR,
+	FLUSH_OR_DISCARD,
+	EMPTY_QUEUE,
+	REL_WRITE,
+	THRESHOLD,
+	MAX_REASONS,
+};
+
+struct mmc_wr_pack_stats {
+	u32 *packing_events;
+	u32 pack_stop_reason[MAX_REASONS];
+	spinlock_t lock;
+	bool enabled;
+	bool print_in_read;
+};
+
 /*
  * MMC device
  */
@@ -246,6 +265,8 @@
 	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */
 
 	struct dentry		*debugfs_root;
+
+	struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
 };
 
 /*
@@ -448,4 +469,8 @@
 extern void mmc_fixup_device(struct mmc_card *card,
 			     const struct mmc_fixup *table);
 
+extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
+			struct mmc_card *card);
+extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
+
 #endif
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9e545f3..2b14423 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1813,6 +1813,15 @@
 			struct hci_cp_auth_requested cp;
 			hci_remove_link_key(hdev, &conn->dst);
 			cp.handle = cpu_to_le16(conn->handle);
+			/*Initiates dedicated bonding as pin or key is missing
+			on remote device*/
+			/*In case if remote device is ssp supported,
+			reduce the security level to MEDIUM if it is HIGH*/
+			if (conn->ssp_mode && conn->auth_initiator &&
+				conn->io_capability != 0x03) {
+				conn->pending_sec_level = BT_SECURITY_HIGH;
+				conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+			}
 			hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
 							sizeof(cp), &cp);
 			hci_dev_unlock(hdev);
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index f7cb424..16c623c 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -44,8 +44,8 @@
     "alignment.c:720",
     "async.c:122",
     "async.c:270",
-    "block.c:880",
-    "block.c:881",
+    "block.c:885",
+    "block.c:886",
     "dir.c:43",
     "dm.c:1053",
     "dm.c:1080",
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index a62541a..284320d 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -604,6 +604,7 @@
 	case SLIMBUS_3_RX:
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
@@ -1127,17 +1128,16 @@
 static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
 				unsigned int tx_num, unsigned int *tx_slot,
 				unsigned int rx_num, unsigned int *rx_slot)
-
 {
 	int rc = 0;
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	unsigned int i = 0;
 
-	dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
-							dai->id);
+	dev_dbg(dai->dev, "%s: dai_id = %d\n", __func__, dai->id);
 	switch (dai->id) {
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_3_RX:
 	case SLIMBUS_4_RX:
 		/* channel number to be between 128 and 255. For RX port
@@ -1472,6 +1472,22 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_rx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+		SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =	192000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
 	.capture = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -1545,6 +1561,10 @@
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_1_tx_dai);
 		break;
+	case SLIMBUS_2_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_2_rx_dai);
+		break;
 	case SLIMBUS_2_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_2_tx_dai);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 9f058b9..51ef359 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -147,6 +147,7 @@
 	case HDMI_RX:
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_3_RX:
 	case INT_BT_SCO_RX:
 	case INT_BT_A2DP_RX:
@@ -206,6 +207,7 @@
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_RX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_RX:
 	case INT_BT_SCO_RX:
@@ -272,6 +274,7 @@
 	case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
 	case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
 	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
+	case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
 	case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
 	case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
@@ -307,6 +310,7 @@
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_RX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_RX:
 	case SLIMBUS_4_RX: