diff mbox

[6/8,RFC] CAIF Protocol Stack

Message ID 1253727091-10383-1-git-send-email-sjur.brandeland@stericsson.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

sjur.brandeland@stericsson.com Sept. 23, 2009, 5:31 p.m. UTC
From: Kim Lilliestierna <Kim.xx.Lilliestierna@ericsson.com>

Signed-off-by: sjur.brandeland@stericsson.com

---
 drivers/net/caif/Kconfig      |   64 +++
 drivers/net/caif/Makefile     |   29 ++
 drivers/net/caif/chnl_tty.c   |  220 +++++++++++
 drivers/net/caif/phyif_loop.c |  309 +++++++++++++++
 drivers/net/caif/phyif_ser.c  |  189 +++++++++
 drivers/net/caif/phyif_shm.c  |  870 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/caif/shm.h        |   95 +++++
 drivers/net/caif/shm_cfgifc.c |   60 +++
 drivers/net/caif/shm_mbxifc.c |   98 +++++
 drivers/net/caif/shm_smbx.c   |   81 ++++
 10 files changed, 2015 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/caif/Kconfig
 create mode 100644 drivers/net/caif/Makefile
 create mode 100644 drivers/net/caif/chnl_tty.c
 create mode 100644 drivers/net/caif/phyif_loop.c
 create mode 100644 drivers/net/caif/phyif_ser.c
 create mode 100644 drivers/net/caif/phyif_shm.c
 create mode 100644 drivers/net/caif/shm.h
 create mode 100644 drivers/net/caif/shm_cfgifc.c
 create mode 100644 drivers/net/caif/shm_mbxifc.c
 create mode 100644 drivers/net/caif/shm_smbx.c

Comments

Randy Dunlap Sept. 24, 2009, 4 a.m. UTC | #1
On Wed, 23 Sep 2009 19:31:31 +0200 sjur.brandeland@stericsson.com wrote:

> From: Kim Lilliestierna <Kim.xx.Lilliestierna@ericsson.com>
> 
> Signed-off-by: sjur.brandeland@stericsson.com
> 
> ---
>  drivers/net/caif/Kconfig      |   64 +++
>  drivers/net/caif/Makefile     |   29 ++
>  drivers/net/caif/chnl_tty.c   |  220 +++++++++++
>  drivers/net/caif/phyif_loop.c |  309 +++++++++++++++
>  drivers/net/caif/phyif_ser.c  |  189 +++++++++
>  drivers/net/caif/phyif_shm.c  |  870 +++++++++++++++++++++++++++++++++++++++++
>  drivers/net/caif/shm.h        |   95 +++++
>  drivers/net/caif/shm_cfgifc.c |   60 +++
>  drivers/net/caif/shm_mbxifc.c |   98 +++++
>  drivers/net/caif/shm_smbx.c   |   81 ++++
>  10 files changed, 2015 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/caif/Kconfig
>  create mode 100644 drivers/net/caif/Makefile
>  create mode 100644 drivers/net/caif/chnl_tty.c
>  create mode 100644 drivers/net/caif/phyif_loop.c
>  create mode 100644 drivers/net/caif/phyif_ser.c
>  create mode 100644 drivers/net/caif/phyif_shm.c
>  create mode 100644 drivers/net/caif/shm.h
>  create mode 100644 drivers/net/caif/shm_cfgifc.c
>  create mode 100644 drivers/net/caif/shm_mbxifc.c
>  create mode 100644 drivers/net/caif/shm_smbx.c
> 
> diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
> new file mode 100644
> index 0000000..3cbe302
> --- /dev/null
> +++ b/drivers/net/caif/Kconfig
> @@ -0,0 +1,64 @@
> +#
> +# CAIF net configurations
> +#
> +
> +if CAIF
> +
> +# Include physical drivers
> +# should be broken out into its own config file
> +# source "drivers/net/caif/Kconfig"
> +
> +# Some options here should be mande platform dependent

                                 made

> +
> +comment "CAIF physical drivers"
> +
> +config CAIF_TTY
> +	tristate "CAIF TTY transport driver "

	no trailing space, please (before the final ")

> +	default CAIF
> +	---help---
> +	The CAIF TTY transport driver
> +	If sou say yes here you will also need to build a users space utility to set the line disicpline on the the

	If you ......                                     userspace [or user space]

	drop final (duplicate) "the" above.

> +	tty, see Documentation/net/caif/examples/linedsc
> +
> +config CAIF_SHM
> +	tristate "CAIF shared memory transport driver"
> +	default n
> +	---help---
> +	The caif low level driver for the shared memory driver

	End sentences with a period ('.').

> +	Be aware that if you enable this you need to also enable a low level shared memory driver

	End above with period.  Begin below with "The".

> +        the default is to include the loopback test driver.
> +
> +config CAIF_LOOPBACK
> +	tristate "CAIF loopback driver test driver"
> +	default CAIF
> +	---help---
> +	Loopback test driver
> +
> +if CAIF_SHM
> +
> +comment "CAIF shared memory low level physical drivers"
> +
> +config CAIF_SHM_LOOPBACK
> +	tristate "Caif shared memory loopback driver"
> +	default CAIF_USE_SHM
> +	---help---
> +	loop back driver that emulates a real shared memory transport
> +	mainly used for debugging.
> +
> +config CAIF_MBXIF
> +	tristate "Caif shared mailbox interface"
> +	default CAIF_SHM
> +	---help---
> +	Generic shared mailbox interface
> +
> +config CAIF_SMBX
> +	tristate "Use Simluated Mail box"
> +	default CAIF_MBXIF
> +	---help---
> +	Answer y if you whant to use a simulated mail box interface for caif shared memory transport

	                want
	End above sentence with a period.

> +	Mainly used for debugging and as example driver
> +	This can also be built as a module

Ditto.

> +
> +endif #CAIF_USE_SHM
> +
> +endif # CAIF



---
~Randy
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stefano Babic Oct. 5, 2009, 3:17 p.m. UTC | #2
sjur.brandeland@stericsson.com wrote:
> From: Kim Lilliestierna <Kim.xx.Lilliestierna@ericsson.com>
> 
> Signed-off-by: sjur.brandeland@stericsson.com

Hi Sjur,

>  drivers/net/caif/chnl_tty.c   |  220 +++++++++++

There is no rule in drivers/net/caif/Makefile regarding this file and it
is not mentioned in the documentation. Is there anything missing ? I
supposed the serial physical layer is implemented in phyif_ser.c.

Regards,
Stefano
sjur.brandeland@stericsson.com Oct. 6, 2009, 7:06 p.m. UTC | #3
Stefano Babic wrote:
>>  drivers/net/caif/chnl_tty.c   |  220 +++++++++++
> There is no rule in drivers/net/caif/Makefile regarding this file and
> it is not mentioned in the documentation. Is there anything missing ?
> I supposed the serial physical layer is implemented in phyif_ser.c.  

The chnl_tty.c is a simple line-discipline providing a CAIF TTY to user space, it is
obsolete and will removed from my next patch-set.
We have put our effort into stabilizing the character device (chnl_chr.c) instead.

BR/Sjur Brændeland

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
new file mode 100644
index 0000000..3cbe302
--- /dev/null
+++ b/drivers/net/caif/Kconfig
@@ -0,0 +1,64 @@ 
+#
+# CAIF net configurations
+#
+
+if CAIF
+
+# Include physical drivers
+# should be broken out into its own config file
+# source "drivers/net/caif/Kconfig"
+
+# Some options here should be mande platform dependent
+
+comment "CAIF physical drivers"
+
+config CAIF_TTY
+	tristate "CAIF TTY transport driver "
+	default CAIF
+	---help---
+	The CAIF TTY transport driver
+	If sou say yes here you will also need to build a users space utility to set the line disicpline on the the
+	tty, see Documentation/net/caif/examples/linedsc
+
+config CAIF_SHM
+	tristate "CAIF shared memory transport driver"
+	default n
+	---help---
+	The caif low level driver for the shared memory driver
+	Be aware that if you enable this you need to also enable a low level shared memory driver
+        the default is to include the loopback test driver.
+
+config CAIF_LOOPBACK
+	tristate "CAIF loopback driver test driver"
+	default CAIF
+	---help---
+	Loopback test driver
+
+if CAIF_SHM
+
+comment "CAIF shared memory low level physical drivers"
+
+config CAIF_SHM_LOOPBACK
+	tristate "Caif shared memory loopback driver"
+	default CAIF_USE_SHM
+	---help---
+	loop back driver that emulates a real shared memory transport
+	mainly used for debugging.
+
+config CAIF_MBXIF
+	tristate "Caif shared mailbox interface"
+	default CAIF_SHM
+	---help---
+	Generic shared mailbox interface
+
+config CAIF_SMBX
+	tristate "Use Simluated Mail box"
+	default CAIF_MBXIF
+	---help---
+	Answer y if you whant to use a simulated mail box interface for caif shared memory transport
+	Mainly used for debugging and as example driver
+	This can also be built as a module
+
+endif #CAIF_USE_SHM
+
+endif # CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
new file mode 100644
index 0000000..f983289
--- /dev/null
+++ b/drivers/net/caif/Makefile
@@ -0,0 +1,29 @@ 
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_FLAGS+=-DCAIF_DEBUG_ON
+endif
+
+
+ccflags-y := -DCAIF_KERNEL -DKERN_VERSION_2_6_27 $(CAIF_FLAGS) -Iinclude/net/caif -Iinclude/linux/caif -Iinclude/net/caif/generic
+
+
+clean-dirs:= .tmp_versions
+clean-files:= Module.symvers modules.order *.cmd *~ \
+
+
+# --- Physical drivers --
+# Serial interface
+obj-$(CONFIG_CAIF_TTY) += phyif_ser.o
+
+# Loop back
+obj-$(CONFIG_CAIF_LOOPBACK) += phyif_loop.o
+
+# Shared memmory
+obj-$(CONFIG_CAIF_SHM) += phyif_shm.o
+
+# Mail box geneirc
+obj-$(CONFIG_CAIF_MBXIF) += shm_mbxifc.o
+
+# Simulated mail box
+obj-$(CONFIG_CAIF_SMBX) += shm_smbx.o
+
+export-objs := caif_chr.o caif_test_chdev.o caif_kapi_test.o
diff --git a/drivers/net/caif/chnl_tty.c b/drivers/net/caif/chnl_tty.c
new file mode 100644
index 0000000..03fe0d3
--- /dev/null
+++ b/drivers/net/caif/chnl_tty.c
@@ -0,0 +1,220 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include "caif_layer.h"
+#include "cfcnfg.h"
+#include "cfpkt.h"
+
+#include "caif_chr.h"
+#include "caif_ioctl.h"
+
+MODULE_LICENSE("GPL");
+
+#define TTY_CHNL_DEVICES 1
+
+static bool tty_registered;
+
+struct chnl_tty {
+	layer_t chnl;
+	struct tty_driver *tty_drv;
+	struct tty_struct *tty;
+};
+
+static struct chnl_tty ttydev;
+
+static int chnl_recv_cb(layer_t *layr, cfpkt_t *pkt)
+{
+	unsigned char *flip = NULL;
+	caif_packet_funcs_t f;
+	int len;
+	size_t max;
+	int count;
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	len = cfpkt_getlen(pkt);
+
+	printk(KERN_INFO "AT received: %d bytes.\n", len);
+
+	/* Get a buffer from the TTY framework. */
+	count = tty_prepare_flip_string(ttydev.tty, &flip, len);
+
+	if (len > count) {
+		printk(KERN_INFO
+		       "TTY buffer to small, dropping %d bytes.\n",
+		       (len - count));
+	}
+
+	/* Check max length that can be copied. */
+	max = len > count ? count : len;
+
+	/* Extract packet to the TTY buffer. */
+	f.cfpkt_extract(pkt, flip, count, &max);
+
+	/* Liberate packet. */
+	f.cfpkt_destroy(pkt);
+
+	/* Push data to the ldisc. */
+	tty_schedule_flip(ttydev.tty);
+
+	return 0;
+}
+
+static void chnl_flowctrl_cb(layer_t *layr, caif_flowctrl_t on)
+{
+	printk("AT flowctrl func called flow: %s.\n",
+	       on == CAIF_FLOWCTRL_ON ? "ON" : "OFF or INIT");
+
+	if (on == CAIF_FLOWCTRL_INIT && tty_registered == false) {
+		/* Register a tty device. */
+		struct device *dev =
+		    tty_register_device(ttydev.tty_drv, 0, NULL);
+		if (IS_ERR(dev)) {
+			int result = PTR_ERR(dev);
+			printk(KERN_WARNING
+			       "chnl: err: %d, can't register tty device.\n",
+			       result);
+			goto err_tty_device_register_failed;
+		}
+		tty_registered = true;
+	}
+
+err_tty_device_register_failed:
+	return;
+}
+
+int chnl_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	ttydev.tty = tty;
+
+	return 0;
+}
+
+void chnl_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	ttydev.tty = NULL;
+}
+
+int chnl_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	cfpkt_t *pkt = NULL;
+	caif_packet_funcs_t f;
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	/* Create a caif packet based on the tty buffer. */
+	pkt = f.cfpkt_create_xmit_pkt(buf, count);
+	if (!pkt) {
+		printk(KERN_INFO "chnl_tty_write: cfpkt_create failed.\n");
+		goto err_cfpkt_create;
+	}
+
+	/* Send the packet down the stack. */
+	ttydev.chnl.dn->transmit(ttydev.chnl.dn, NULL, pkt);
+
+	return count;
+
+err_cfpkt_create:
+	return 0;
+}
+
+struct tty_operations chnl_tty_ops = {
+	.open = chnl_tty_open,
+	.close = chnl_tty_close,
+	.write = chnl_tty_write,
+};
+
+void chnl_tty_exit_module(void)
+{
+	if (ttydev.tty) {
+		tty_unregister_device(ttydev.tty_drv, 0);
+		ttydev.tty = NULL;
+	}
+	tty_unregister_driver(ttydev.tty_drv);
+	put_tty_driver(ttydev.tty_drv);
+	ttydev.tty_drv = NULL;
+}
+
+int chnl_tty_init_module(void)
+{
+	struct caif_service_config config;
+	int result;
+
+	ttydev.tty_drv = alloc_tty_driver(TTY_CHNL_DEVICES);
+	if (ttydev.tty_drv == NULL) {
+		printk(KERN_WARNING
+		       "chnl_tty_init_module: err: "
+		       "can't allocate tty driver.\n");
+		result = -ENOMEM;
+		goto err_alloc_tty_driver_failed;
+	}
+
+	ttydev.tty_drv->driver_name = "caif_tty";
+	ttydev.tty_drv->name = "cftty";
+	ttydev.tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+	ttydev.tty_drv->subtype = SERIAL_TYPE_NORMAL;
+	ttydev.tty_drv->init_termios = tty_std_termios;
+	ttydev.tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+
+	/* Register the TTY driver. */
+	tty_set_operations(ttydev.tty_drv, &chnl_tty_ops);
+
+	result = tty_register_driver(ttydev.tty_drv);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "chnl_tty_init_module: err: "
+		       "%d, can't register tty driver.\n",
+		       result);
+		goto err_tty_driver_register_failed;
+	}
+
+	/* Fill in channel information. */
+	ttydev.chnl.receive = chnl_recv_cb;
+	ttydev.chnl.flowctrl = chnl_flowctrl_cb;
+
+	memset(&config, 0, sizeof(config));
+	config.service = CAIF_SRVC_AT;
+	config.phy_type = CAIF_PHY_LOW_LAT;
+	config.priority = CAIF_PRIO_NORMAL;
+
+	/* Register this channel. */
+	result = caifdev_adapt_register(&config, &ttydev.chnl);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "chnl_tty_init_module: err:"
+		       " %d, can't register channel.\n",
+		       result);
+		goto err_register_chnl;
+	}
+
+	return result;
+
+err_register_chnl:
+	tty_unregister_driver(ttydev.tty_drv);
+err_tty_driver_register_failed:
+	put_tty_driver(ttydev.tty_drv);
+	ttydev.tty_drv = NULL;
+err_alloc_tty_driver_failed:
+	return -ENODEV;
+}
+
+module_init(chnl_tty_init_module);
+module_exit(chnl_tty_exit_module);
diff --git a/drivers/net/caif/phyif_loop.c b/drivers/net/caif/phyif_loop.c
new file mode 100644
index 0000000..2bfa42b
--- /dev/null
+++ b/drivers/net/caif/phyif_loop.c
@@ -0,0 +1,309 @@ 
+/*
+ *	Copyright (C) ST-Ericsson AB 2009
+ *
+ *	Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *		Per Sigmond / Per.Sigmond@stericsson.com
+ *
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+
+
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+/* Caif header files. */
+#include "caif_log.h"
+#include "caif_layer.h"
+#include "cfcnfg.h"
+#include "cfpkt.h"
+
+#include "caif_chr.h"
+
+#include <linux/delay.h>
+
+
+MODULE_LICENSE("GPL");
+
+
+
+static int reentrant;
+static int direct;
+static int serial;
+module_param(reentrant, bool, S_IRUGO);
+module_param(direct, bool, S_IRUGO);
+module_param(serial, bool, S_IRUGO);
+MODULE_PARM_DESC(reentrant,
+		 "Reentrant or not (defualt is workqueue implementation)");
+MODULE_PARM_DESC(direct,
+		 "Direct mode, looping packets directly back up the stack");
+
+static layer_t cf_phy;
+static layer_t loop_phy;
+static spinlock_t ring_buffer_lock;
+
+
+/* Start ring buffer */
+#define RING_MAX_BUFFERS 16384
+
+struct ring_buffer_element {
+	struct _cfpkt_t *cfpkt;
+};
+
+static struct {
+	struct ring_buffer_element ring_buffer[RING_MAX_BUFFERS];
+	int head_index;
+	int tail_index;
+} my_ring_buffer;
+
+#define ring_buffer_index_plus_one(index) \
+    ((index+1) < RING_MAX_BUFFERS ? (index + 1) : 0)
+
+#define ring_buffer_increment_tail(rb) \
+    ((rb)->tail_index = ring_buffer_index_plus_one((rb)->tail_index))
+
+#define ring_buffer_increment_head(rb) \
+    ((rb)->head_index = ring_buffer_index_plus_one((rb)->head_index))
+
+#define ring_buffer_empty(rb) ((rb)->head_index == (rb)->tail_index)
+#define ring_buffer_full(rb) (ring_buffer_index_plus_one((rb)->head_index)\
+			      == (rb)->tail_index)
+#define ring_buffer_tail_element(rb) ((rb)->ring_buffer[(rb)->tail_index])
+#define ring_buffer_head_element(rb) ((rb)->ring_buffer[(rb)->head_index])
+#define ring_buffer_size(rb) (((rb)->head_index >= (rb)->tail_index)) ?\
+  ((rb)->head_index - (rb)->tail_index) : \
+    (RING_MAX_BUFFERS - ((rb)->tail_index - (rb)->head_index))
+/* End ring buffer */
+
+
+
+static void work_func(struct work_struct *work);
+static struct workqueue_struct *ploop_work_queue;
+static DECLARE_WORK(loop_work, work_func);
+static wait_queue_head_t buf_available;
+
+
+#define phyif_assert(assert) BUG_ON(!(assert))
+
+
+
+
+
+
+
+
+
+
+
+
+
+static void work_func(struct work_struct *work)
+{
+
+	CAIFLOG_ENTER("");
+
+	while (!ring_buffer_empty(&my_ring_buffer)) {
+		struct _cfpkt_t *cfpkt;
+
+		/* Get packet */
+		cfpkt = ring_buffer_tail_element(&my_ring_buffer).cfpkt;
+		ring_buffer_tail_element(&my_ring_buffer).cfpkt = NULL;
+
+		ring_buffer_increment_tail(&my_ring_buffer);
+
+		/* Wake up writer */
+		wake_up_interruptible(&buf_available);
+
+
+		/* Push received packet up the caif stack. */
+		cf_phy.up->receive(cf_phy.up, cfpkt);
+
+	}
+
+	/* Release access to loop queue. */
+	CAIFLOG_EXIT("");
+}
+
+static int cf_phy_modemcmd(layer_t *layr, caif_modemcmd_t ctrl)
+{
+	switch (ctrl) {
+	case _CAIF_MODEMCMD_PHYIF_USEFULL:
+		CAIFLOG_TRACE("phyif_loop:Usefull");
+
+		try_module_get(THIS_MODULE);
+		break;
+	case _CAIF_MODEMCMD_PHYIF_USELESS:
+		CAIFLOG_TRACE("phyif_loop:Useless");
+		module_put(THIS_MODULE);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int cf_phy_tx(layer_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	int ret;
+	CAIFLOG_ENTER("");
+
+	/* Push received packet up the loop stack. */
+	ret = loop_phy.up->receive(loop_phy.up, pkt);
+
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+
+static int
+loop_phy_tx_reent(layer_t *layr, transmt_info *info, struct _cfpkt_t *cfpkt)
+{
+	CAIFLOG_ENTER("");
+
+	/* Push received packet up the caif stack. */
+	cf_phy.up->receive(cf_phy.up, cfpkt);
+
+	CAIFLOG_EXIT("");
+	return 0;
+}
+
+
+static int
+loop_phy_tx(layer_t *layr, transmt_info *info, struct _cfpkt_t *cfpkt)
+{
+
+	CAIFLOG_ENTER("");
+
+	/* Block writer as long as ring buffer is full */
+
+	spin_lock(&ring_buffer_lock);
+	/*phyif_assert( !ring_buffer_full(&my_ring_buffer) );*/
+
+	while (ring_buffer_full(&my_ring_buffer)) {
+		spin_unlock(&ring_buffer_lock);
+
+		if (wait_event_interruptible
+		    (buf_available,
+		     !ring_buffer_full(&my_ring_buffer)) == -ERESTARTSYS) {
+			printk(KERN_WARNING
+			       "loop_phy_tx: "
+			       "wait_event_interruptible woken by a signal\n");
+			return -ERESTARTSYS;
+		}
+
+
+		spin_lock(&ring_buffer_lock);
+	}
+
+
+	ring_buffer_head_element(&my_ring_buffer).cfpkt = cfpkt;
+	ring_buffer_increment_head(&my_ring_buffer);
+	spin_unlock(&ring_buffer_lock);
+
+	/* Add this  work to the queue as we don't want to
+	 * loop in the same context.
+	 */
+	(void) queue_work(ploop_work_queue, &loop_work);
+
+	CAIFLOG_EXIT("");
+	return 0;
+}
+
+static int cf_phy_tx_direct(layer_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	int ret;
+
+	CAIFLOG_ENTER("");
+	CAIFLOG_TRACE("[%s] up:%p pkt:%p\n", __func__, cf_phy.up,
+		    pkt);
+	/* Push received packet back up the caif stack,
+	 * via loop_phy_tx's work-queue */
+	ret = loop_phy_tx(layr, info, pkt);
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+
+static int __init phyif_loop_init(void)
+{
+	int result;
+
+	CAIFLOG_ENTER("");
+	printk("\nCompiled:%s:%s\nreentrant=%s direct=%s\n",
+	       __DATE__, __TIME__,
+	       (reentrant ? "yes" : "no"),
+	       (direct ? "yes" : "no"));
+	/* Fill in some information about our PHYs. */
+	if (direct) {
+		cf_phy.transmit = cf_phy_tx_direct;
+		cf_phy.receive = NULL;
+	} else {
+		cf_phy.transmit = cf_phy_tx;
+		cf_phy.receive = NULL;
+	}
+	if (reentrant)
+		loop_phy.transmit = loop_phy_tx_reent;
+	else
+		loop_phy.transmit = loop_phy_tx;
+
+	loop_phy.receive = NULL;
+	cf_phy.modemcmd = cf_phy_modemcmd;
+
+	/* Create work thread. */
+	ploop_work_queue = create_singlethread_workqueue("phyif_loop");
+
+	init_waitqueue_head(&buf_available);
+
+	/* Initialize ring buffer */
+	memset(&my_ring_buffer, 0, sizeof(my_ring_buffer));
+	spin_lock_init(&ring_buffer_lock);
+	cf_phy.id = -1;
+	if (serial)
+		result =
+		    caifdev_phy_register(&cf_phy, CFPHYTYPE_SERIAL,
+					 CFPHYPREF_UNSPECIFIED);
+	else
+		result =
+		    caifdev_phy_register(&cf_phy, CFPHYTYPE_MSL,
+					 CFPHYPREF_UNSPECIFIED);
+
+	printk(KERN_WARNING "phyif_loop: ID = %d\n", cf_phy.id);
+
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "phyif_loop: err: %d, can't register phy.\n", result);
+	}
+
+	if (serial)
+		result =
+		    caifdev_phy_loop_register(&loop_phy, CFPHYTYPE_SERIAL);
+	else
+		result = caifdev_phy_loop_register(&loop_phy, CFPHYTYPE_MSL);
+
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "phyif_loop: err: %d, can't register loop phy.\n",
+		       result);
+	}
+
+	printk(KERN_WARNING "phyif_loop: ID = %d\n", cf_phy.id);
+	CAIFLOG_EXIT("");
+	return result;
+}
+
+static void phyif_loop_exit(void)
+{
+	printk(KERN_WARNING "phyif_loop: ID = %d\n", cf_phy.id);
+
+	caifdev_phy_unregister(&cf_phy);
+	cf_phy.id = -1;
+}
+
+module_init(phyif_loop_init);
+module_exit(phyif_loop_exit);
diff --git a/drivers/net/caif/phyif_ser.c b/drivers/net/caif/phyif_ser.c
new file mode 100644
index 0000000..5dc3da6
--- /dev/null
+++ b/drivers/net/caif/phyif_ser.c
@@ -0,0 +1,189 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+
+#include "caif_layer.h"
+#include "cfcnfg.h"
+#include "cfpkt.h"
+#include "caif_chr.h"
+
+
+MODULE_LICENSE("GPL");
+
+module_param(serial_use_stx, bool, S_IRUGO);
+MODULE_PARM_DESC(serial_use_stx, "STX enabled or not.");
+
+#define WRITE_BUF_SIZE	256
+#define READ_BUF_SIZE	256
+
+unsigned char sbuf_wr[WRITE_BUF_SIZE];
+
+layer_t ser_phy;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+static struct tty_ldisc_ops phyif_ldisc;
+#else
+static struct tty_ldisc phyif_ldisc;
+#endif				/* KERN_VERSION_2_6_27 */
+
+struct tty_struct *pser_tty;
+
+
+static bool tx_started;
+
+static int ser_open(struct tty_struct *tty)
+{
+	int result;
+
+	pser_tty = tty;
+
+	/* Configure the attached TTY. */
+
+	/* Register physical interface. */
+	result =
+	    caifdev_phy_register(&ser_phy, CFPHYTYPE_SERIAL,
+				 CFPHYPREF_LOW_LAT);
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "phyif_ser: err: %d, can't register phy.\n", result);
+	}
+
+	return result;
+}
+
+static void ser_receive(struct tty_struct *tty, const u8 *data,
+			char *flags, int count)
+{
+	cfpkt_t *pkt = NULL;
+	caif_packet_funcs_t f;
+	/*int i; */
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+
+	/* Workaround for garbage at start of transmission,
+	 * only enable if STX handling is not enables */
+	if (!serial_use_stx && !tx_started) {
+		printk(KERN_WARNING
+		       "Bytes received before first transmission."
+		       " Bytes discarded. \n");
+		return;
+	}
+
+	/* Get a suitable caif packet and copy in data. */
+	pkt = f.cfpkt_create_recv_pkt(data, count);
+
+	/* Push received packet up the stack. */
+	ser_phy.up->receive(ser_phy.up, pkt);
+}
+
+
+int ser_phy_tx(layer_t *layr, transmt_info *info, struct _cfpkt_t *cfpkt)
+{
+	size_t tty_wr, actual_len;
+	bool cont;
+	caif_packet_funcs_t f;
+	/*int i; */
+
+	if (!pser_tty)
+		return CFGLU_ENOTCONN;
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	/* NOTE: This workaround is not really needed when STX is enabled.
+	 *  Remove? */
+	if (tx_started == false)
+		tx_started = true;
+
+
+	do {
+		char *bufp;
+		/* By default we assume that we will extract
+		 * all data in one go. */
+		cont = false;
+
+		/* Extract data from the packet. */
+		f.cfpkt_extract(cfpkt, sbuf_wr, WRITE_BUF_SIZE, &actual_len);
+
+		/* Check if we need to extract more data. */
+		if (actual_len == WRITE_BUF_SIZE)
+			cont = true;
+
+		bufp = sbuf_wr;
+		/* Write the data on the tty driver.
+		 * NOTE: This loop will be spinning until UART is ready for
+		 *	 sending data.
+		 *	 It might be looping forever if we get UART problems.
+		 *	 This part should be re-written!
+		 */
+		do {
+			tty_wr =
+			    pser_tty->ops->write(pser_tty, bufp, actual_len);
+			/* When not whole buffer is written,
+			 * forward buffer pointer and try again */
+			actual_len -= tty_wr;
+			bufp += tty_wr;
+		} while (actual_len);
+	} while (cont == true);
+
+	/* The packet is sent. As we have come to the end of the
+	 * line we need to free the packet. */
+	f.cfpkt_destroy(cfpkt);
+
+	return 0;
+}
+
+static int __init phyif_ser_init(void)
+{
+	int result;
+
+	/* Fill in some information about our PHY. */
+	ser_phy.transmit = ser_phy_tx;
+	ser_phy.receive = NULL;
+	ser_phy.ctrlcmd = NULL;
+	ser_phy.modemcmd = NULL;
+
+	memset(&phyif_ldisc, 0, sizeof(phyif_ldisc));
+	phyif_ldisc.magic = TTY_LDISC_MAGIC;
+	phyif_ldisc.name = "n_phyif";
+	phyif_ldisc.open = ser_open;
+	phyif_ldisc.receive_buf = ser_receive;
+	phyif_ldisc.owner = THIS_MODULE;
+
+	result = tty_register_ldisc(N_MOUSE, &phyif_ldisc);
+
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "phyif_ser: err: %d, can't register ldisc.\n", result);
+		return result;
+	}
+
+	return result;
+}
+
+static void phyif_ser_exit(void)
+{
+	(void) tty_unregister_ldisc(N_MOUSE);
+}
+
+module_init(phyif_ser_init);
+module_exit(phyif_ser_exit);
+
+MODULE_ALIAS_LDISC(N_MOUSE);
diff --git a/drivers/net/caif/phyif_shm.c b/drivers/net/caif/phyif_shm.c
new file mode 100644
index 0000000..c192d11
--- /dev/null
+++ b/drivers/net/caif/phyif_shm.c
@@ -0,0 +1,870 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+#include <linux/semaphore.h>
+#else
+#include <linux/semaphore.h>
+#endif				/* KERN_VERSION_2_6_27 */
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+#ifdef PHYIF_SHM_USE_DMA
+#include <linux/dma-mapping.h>
+#endif				/* PHYIF_SHM_USE_DMA */
+#include <linux/io.h>
+
+/* Caif header files. */
+#include "caif_layer.h"
+#include "cfcnfg.h"
+#include "cfpkt.h"
+
+/* Caif linux header files. */
+#include "caif_chr.h"
+#include "shm.h"
+
+MODULE_LICENSE("GPL");
+
+#define SHM_INSTANCES		1
+
+static char *mbxifc_name = "cfmbx";
+module_param(mbxifc_name, charp, S_IRUGO);
+MODULE_PARM_DESC(mbxifc_name,
+		 "Name of the shared memory mailbox interface.");
+
+static char *mbxcfg_name = "cfcfg";
+module_param(mbxcfg_name, charp, S_IRUGO);
+MODULE_PARM_DESC(mbxcfg_name,
+		 "Name of the shared memory configuration interface.");
+
+#define SHM_CMD_DUMMY		0x00
+
+#define SHM_CMD_MASK		(0x3F << 10)
+#define SHM_FULL_MASK		(0x0F << 0)
+#define SHM_EMPTY_MASK		(0x0F << 4)
+
+#define SHM_SET_CMD(x)		((x & 0x3F) << 10)
+#define SHM_GET_CMD(x)		((x >>	10) & 0x3F)
+
+#define SHM_SET_FULL(x)		(((x+1) & 0x0F) << 0)
+#define SHM_GET_FULL(x)		(((x >> 0) & 0x0F) - 1)
+
+#define SHM_SET_EMPTY(x)	(((x+1) & 0x0F) << 4)
+#define SHM_GET_EMPTY(x)	(((x >> 4) & 0x0F) - 1)
+
+typedef struct {
+	/* Offset from start of shared memory area to start of
+	 * shared memory CAIF frame. */
+	uint32 frm_ofs;
+	/* Length of CAIF frame. */
+	uint32 frm_len;
+} shm_pck_desc_t, *pshm_pck_desc_t;
+
+typedef struct {
+	/* Number of bytes of padding before the CAIF frame. */
+	uint8 hdr_ofs;
+} shm_caif_frm_t, *pshm_caif_frm_t;
+
+/* Maximum number of CAIF buffers per shared memory buffer. */
+#define SHM_MAX_CAIF_FRMS_PER_BUF	10
+
+/* Size in bytes of the descriptor area
+ * (With end of descriptor signalling). */
+#define SHM_CAIF_DESC_SIZE	((SHM_MAX_CAIF_FRMS_PER_BUF + 1) * \
+				  sizeof(shm_pck_desc_t))
+
+/* Offset to the first CAIF frame within a shared memory buffer.
+ * Aligned on 32 bytes. */
+#define SHM_CAIF_FRM_OFS	(SHM_CAIF_DESC_SIZE + (SHM_CAIF_DESC_SIZE % 32))
+/* Number of bytes for CAIF shared memory header. */
+#define SHM_HDR_LEN					1
+/* Number of bytes for alignment of the CAIF service layer payload. */
+#define SHM_PAYLOAD_ALIGN_LEN		4
+/* Number of padding bytes for the complete CAIF frame. */
+#define SHM_FRM_PAD_LEN				4
+
+typedef struct _shm_layer_t {
+	layer_t shm_phy;
+	shm_cfgifc_t *cfg_ifc;
+	shm_mbxifc_t *mbx_ifc;
+	char cfg_name[16];
+	shm_mbxclient_t mbx_client;
+	char mbx_name[16];
+#ifdef PHYIF_SHM_USE_DMA
+	struct dmaifc_t *dma_ifc;
+#endif				/* PHYIF_SHM_USE_DMA */
+	/* Lists for shared memory buffer synchronization and handling. */
+	struct list_head tx_empty_list;
+	struct list_head rx_empty_list;
+	struct list_head tx_pend_list;
+	struct list_head rx_pend_list;
+	struct list_head tx_full_list;
+	struct list_head rx_full_list;
+	struct work_struct sig_work;
+	struct work_struct rx_work;
+	struct work_struct flow_work;
+	struct workqueue_struct *sig_work_queue;
+	struct workqueue_struct *rx_work_queue;
+	struct workqueue_struct *flow_work_queue;
+
+    /* wait queue for sender to check for space to write in mailbox */
+    wait_queue_head_t mbx_space_wq;
+	int tx_empty_available;
+
+} shm_layer_t;
+
+static shm_layer_t shm_layer[SHM_INSTANCES];
+
+/* Shared memory buffer structure. */
+typedef struct {
+	int index;
+	int len;
+	int frames;
+	unsigned char *desc_ptr;
+	int frm_ofs;
+	int phy_addr;
+#ifdef PHYIF_SHM_USE_DMA
+	dma_addr_t *dma_ptr;
+#endif				/* PHYIF_SHM_USE_DMA */
+	struct list_head list;
+} shm_buf_t;
+
+static DEFINE_SPINLOCK(lock);
+
+static void phyif_shm_sig_work_func(struct work_struct *work);
+static void phyif_shm_rx_work_func(struct work_struct *work);
+static void phyif_shm_flow_work_func(struct work_struct *work);
+
+static void phyif_shm_sig_work_func(struct work_struct *work)
+{
+	/* TODO: We assume that this call is not reentrant as
+	 *	 that might change the order of the buffers which
+	 * is not allowed. Option is to lock the whole function.    */
+
+	int ret;
+	uint16 mbox_msg;
+	shm_layer_t *pshm = container_of(work, shm_layer_t, sig_work);
+
+	do {
+		shm_buf_t *pbuf;
+		unsigned long flags;
+
+		/* Initialize mailbox message. */
+		mbox_msg = 0x00;
+
+		spin_lock(&lock);
+
+		/* Check for pending transmit buffers. */
+		if (!list_empty(&pshm->tx_pend_list)) {
+			pbuf =
+			    list_entry(pshm->tx_pend_list.next,
+				       shm_buf_t, list);
+			list_del_init(&pbuf->list);
+
+			/* Release mutex. */
+			spin_unlock(&lock);
+
+			/* Grab spin lock. */
+			spin_lock_irqsave(&lock, flags);
+
+			list_add_tail(&pbuf->list, &pshm->tx_full_list);
+
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* Value index is never changed,
+			 * read access should be safe. */
+			mbox_msg |= SHM_SET_FULL(pbuf->index);
+
+			spin_lock(&lock);
+		}
+
+		/* Check for pending receive buffers. */
+		if (!list_empty(&pshm->rx_pend_list)) {
+
+			pbuf = list_entry(pshm->rx_pend_list.next,
+				       shm_buf_t, list);
+			list_del_init(&pbuf->list);
+
+			/* Release mutex. */
+			spin_unlock(&lock);
+
+			/* Grab spin lock. */
+			spin_lock_irqsave(&lock, flags);
+
+			list_add_tail(&pbuf->list, &pshm->rx_empty_list);
+
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* Value index is never changed,
+			 * read access should be safe. */
+			mbox_msg |= SHM_SET_EMPTY(pbuf->index);
+
+			spin_lock(&lock);
+		}
+
+		/* Release mutex. */
+		spin_unlock(&lock);
+
+		if (mbox_msg) {
+			do {
+				long timeout = 3;
+				ret = pshm->mbx_ifc->send_msg(mbox_msg,
+					pshm->mbx_ifc->priv);
+
+				if (ret) {
+					interruptible_sleep_on_timeout(
+						&pshm->mbx_space_wq, timeout);
+				}
+
+			} while (ret);
+		}
+
+	} while (mbox_msg);
+}
+
+static void phyif_shm_rx_work_func(struct work_struct *work)
+{
+	shm_buf_t *pbuf;
+	caif_packet_funcs_t f;
+	struct _cfpkt_t *pkt;
+	unsigned long flags;
+	shm_layer_t *pshm;
+	/* TODO: We assume that this call is not reentrant as that might
+	 *	 change the order of the buffers which is not possible.
+	 *	 Option is to lock the whole function.	  */
+
+	pshm = container_of(work, shm_layer_t, rx_work);
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	do {
+		pshm_pck_desc_t pck_desc;
+
+		/* Grab spin lock. */
+		spin_lock_irqsave(&lock, flags);
+
+		/* Check for received buffers. */
+	if (list_empty(&pshm->rx_full_list)) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+			break;
+		}
+		pbuf =
+		    list_entry(pshm->rx_full_list.next, shm_buf_t, list);
+		list_del_init(&pbuf->list);
+
+		/* Release spin lock. */
+		spin_unlock_irqrestore(&lock, flags);
+
+		/* Retrieve pointer to start of the packet descriptor area. */
+		pck_desc = (pshm_pck_desc_t) pbuf->desc_ptr;
+
+		/* Check if descriptor contains a CAIF shared memory frame. */
+		while (pck_desc->frm_ofs) {
+			unsigned int frm_buf_ofs;
+			unsigned int frm_pck_ofs;
+			unsigned int frm_pck_len;
+
+			/* Check if offset is within buffer limits (lower). */
+			if (pck_desc->frm_ofs <
+			    (pbuf->phy_addr - shm_base_addr)) {
+				printk(KERN_WARNING
+				       "phyif_shm_rx_work_func:"
+				       " Frame offset too small: %d\n",
+				       pck_desc->frm_ofs);
+				break;
+			}
+
+			/* Check if offset is within buffer limits (higher). */
+			if (pck_desc->frm_ofs >
+			    ((pbuf->phy_addr - shm_base_addr) +
+			     pbuf->len)) {
+				printk(KERN_WARNING
+				       "phyif_shm_rx_work_func:"
+				       " Frame offset too big: %d\n",
+				       pck_desc->frm_ofs);
+				break;
+			}
+
+			/* Calculate offset from start of buffer. */
+			frm_buf_ofs =
+			    pck_desc->frm_ofs - (pbuf->phy_addr -
+						 shm_base_addr);
+
+			/* Calculate offset and length of CAIF packet while
+			 * taking care of the shared memory header. */
+			frm_pck_ofs =
+			    frm_buf_ofs + SHM_HDR_LEN +
+			    (*(pbuf->desc_ptr + frm_buf_ofs));
+			frm_pck_len =
+			    (pck_desc->frm_len - SHM_HDR_LEN -
+			     (*(pbuf->desc_ptr + frm_buf_ofs)));
+
+			/* Check if CAIF packet is within buffer limits. */
+			if ((frm_pck_ofs + pck_desc->frm_len) > pbuf->len) {
+				printk(KERN_WARNING
+				       "phyif_shm_rx_work_func: "
+				       "caif packet too big: offset:"
+				       "%d, len: %d\n",
+				       frm_pck_ofs, pck_desc->frm_len);
+				break;
+			}
+
+			/* Get a suitable caif packet and copy in data. */
+			pkt =
+			    f.cfpkt_create_recv_pkt((pbuf->desc_ptr +
+						     frm_pck_ofs),
+						    frm_pck_len);
+
+			/* Push received packet up the stack. */
+			pshm->shm_phy.up->receive(pshm->shm_phy.up, pkt);
+
+			/* Move to next packet descriptor. */
+			pck_desc++;
+		};
+
+		spin_lock(&lock);
+		list_add_tail(&pbuf->list, &pshm->rx_pend_list);
+		spin_unlock(&lock);
+
+	} while (1);
+
+	/* Schedule signaling work queue. */
+	(void) queue_work(pshm->sig_work_queue, &pshm->sig_work);
+}
+
+static void phyif_shm_flow_work_func(struct work_struct *work)
+{
+	shm_layer_t *pshm;
+
+	pshm = container_of(work, shm_layer_t, flow_work);
+
+	if (!pshm->shm_phy.up->ctrlcmd) {
+		printk(KERN_WARNING "phyif_shm_flow_work_func: No flow up.\n");
+		return;
+	}
+
+	/* Re-enable the flow.*/
+	pshm->shm_phy.up->ctrlcmd(pshm->shm_phy.up,
+		_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND, 0);
+}
+
+static int phyif_shm_mbx_msg_cb(u16 mbx_msg, void *priv)
+{
+	shm_layer_t *pshm;
+	shm_buf_t *pbuf;
+	unsigned long flags;
+
+	pshm = (shm_layer_t *) priv;
+	/* TODO: Do we need the spin locks since this is assumed to be
+	 * called from an IRQ context. */
+
+	/*	 We are also assuming that this call is not be reentrant as
+	 *	 that might change the order of the buffers which is not
+	 *	 possible. Option is to lock the whole function. */
+
+	/* Check for received buffers. */
+	if (mbx_msg & SHM_FULL_MASK) {
+		int idx;
+
+		/* Grab spin lock. */
+		spin_lock_irqsave(&lock, flags);
+
+		/* Check if we have any outstanding buffers. */
+		if (list_empty(&pshm->rx_empty_list)) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* We print even in IRQ context... */
+			printk(KERN_WARNING
+			    "phyif_shm_mbx_msg_cb:"
+			    " No empty Rx buffers to fill: msg:%x \n",
+			    mbx_msg);
+
+			/* Bail out. */
+			goto err_rx_sync;
+		}
+
+		pbuf =
+		    list_entry(pshm->rx_empty_list.next, shm_buf_t, list);
+		idx = pbuf->index;
+
+		/* Check buffer synchronization. */
+		if (idx != SHM_GET_FULL(mbx_msg)) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* We print even in IRQ context... */
+			printk(KERN_WARNING
+			       "phyif_shm_mbx_msg_cb: RX full out of sync:"
+			       " idx:%d, msg:%x \n",
+			       idx, mbx_msg);
+
+			/* Bail out. */
+			goto err_rx_sync;
+		}
+
+		list_del_init(&pbuf->list);
+		list_add_tail(&pbuf->list, &pshm->rx_full_list);
+
+		/* Release spin lock. */
+		spin_unlock_irqrestore(&lock, flags);
+
+		/* Schedule RX work queue. */
+		(void) queue_work(pshm->rx_work_queue, &pshm->rx_work);
+	}
+
+err_rx_sync:
+
+	/* Check for emptied buffers. */
+	if (mbx_msg & SHM_EMPTY_MASK) {
+		int idx;
+
+		/* Grab spin lock. */
+		spin_lock_irqsave(&lock, flags);
+
+		/* Check if we have any outstanding buffers. */
+	if (list_empty(&pshm->tx_full_list)) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* We print even in IRQ context... */
+			printk(KERN_WARNING
+				"phyif_shm_mbx_msg_cb:"
+				" No TX to empty: msg:%x \n",
+			       mbx_msg);
+
+			/* Bail out. */
+			goto err_tx_sync;
+		}
+
+		pbuf =
+		    list_entry(pshm->tx_full_list.next, shm_buf_t, list);
+		idx = pbuf->index;
+
+		/* Check buffer synchronization. */
+		if (idx != SHM_GET_EMPTY(mbx_msg)) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* We print even in IRQ context... */
+			printk(KERN_WARNING
+			       "phyif_shm_mbx_msg_cb: TX empty out of sync:"
+			       " idx:%d, msg:%x \n",
+			       idx, mbx_msg);
+
+			/* Bail out. */
+			goto err_tx_sync;
+		}
+
+		list_del_init(&pbuf->list);
+
+		/* Reset buffer parameters. */
+		pbuf->frames = 0;
+		pbuf->frm_ofs = SHM_CAIF_FRM_OFS;
+
+		list_add_tail(&pbuf->list, &pshm->tx_empty_list);
+
+		/* Check if we have to wake up transmitter. */
+		if (!pshm->tx_empty_available) {
+			pshm->tx_empty_available = 1;
+
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			/* Schedule flow re-enable work queue. */
+			(void) queue_work(pshm->flow_work_queue,
+					  &pshm->flow_work);
+
+		} else {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+		}
+	}
+
+err_tx_sync:
+
+	/* Check for command buffers.
+	if (mbx_msg & SHM_CMD_MASK) {
+	}
+	*/
+
+    return ESUCCESS;
+}
+
+void shm_phy_fctrl(layer_t *layr, caif_ctrlcmd_t on, int phyid)
+{
+	/* We have yet not added flow control. */
+}
+
+static int shm_send_pkt(shm_layer_t *pshm, cfpkt_t *cfpkt, bool append)
+{
+	unsigned long flags;
+	shm_buf_t *pbuf;
+	unsigned int extlen;
+	unsigned int frmlen = 0;
+	pshm_pck_desc_t pck_desc;
+	pshm_caif_frm_t frm;
+	caif_packet_funcs_t f;
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	/* Grab spin lock. */
+	spin_lock_irqsave(&lock, flags);
+
+	if (append) {
+		if (list_empty(&pshm->tx_pend_list)) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+			return CFGLU_ERETRY;
+		}
+
+		/* Get the last pending buffer. */
+		pbuf = list_entry(pshm->tx_pend_list.prev, shm_buf_t, list);
+
+		/* Check that we don't exceed the descriptor area. */
+		if (pbuf->frames >= SHM_MAX_CAIF_FRMS_PER_BUF) {
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+			return CFGLU_ERETRY;
+		}
+	} else {
+		if (list_empty(&pshm->tx_empty_list)) {
+			/* Update blocking condition. */
+			pshm->tx_empty_available = 0;
+
+			/* Release spin lock. */
+			spin_unlock_irqrestore(&lock, flags);
+
+			if (!pshm->shm_phy.up->ctrlcmd) {
+				printk(KERN_WARNING "shm_phy_tx: No flow up.\n");
+				return CFGLU_ERETRY;
+			}
+
+			pshm->shm_phy.up->ctrlcmd(pshm->shm_phy.up,
+				_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, 0);
+
+			return CFGLU_ERETRY;
+		}
+
+		/* Get the first free buffer. */
+		pbuf = list_entry(pshm->tx_empty_list.next, shm_buf_t, list);
+	}
+
+	list_del_init(&pbuf->list);
+
+	/* Release spin lock. */
+	spin_unlock_irqrestore(&lock, flags);
+
+	/* TODO: The CAIF stack will have to give a hint on what is
+	 *	 payload in order to align it. */
+	frm = (pshm_caif_frm_t) (pbuf->desc_ptr + pbuf->frm_ofs);
+	frm->hdr_ofs = 0;
+	frmlen += SHM_HDR_LEN + frm->hdr_ofs;
+
+	/* Add length of CAIF frame. */
+	frmlen += f.cfpkt_getlen(cfpkt);
+
+	/* Add tail padding if needed. */
+	if (frmlen % SHM_FRM_PAD_LEN)
+		frmlen += SHM_FRM_PAD_LEN - (frmlen % SHM_FRM_PAD_LEN);
+
+
+	/* Verify that packet, header and additional padding can fit
+	 * within the buffer frame area. */
+	if (frmlen >= (pbuf->len - pbuf->frm_ofs)) {
+		if (append) {
+			/* Put back packet as end of pending queue. */
+			list_add_tail(&pbuf->list, &pshm->tx_pend_list);
+			return CFGLU_ENOSPC;
+		} else {
+			/* Put back packet as start of empty queue. */
+			list_add(&pbuf->list, &pshm->tx_empty_list);
+			return CFGLU_ENOSPC;
+		}
+	}
+
+	/* Extract data from the packet to the shared memory CAIF frame
+	 * taking into account the shared memory header byte and possible
+	 * payload alignment bytes. */
+
+	f.cfpkt_extract(cfpkt,
+			(pbuf->desc_ptr + pbuf->frm_ofs + SHM_HDR_LEN +
+			 frm->hdr_ofs), pbuf->len, &extlen);
+
+	/* Fill in the shared memory packet descriptor area. */
+	pck_desc = (pshm_pck_desc_t) (pbuf->desc_ptr);
+	/* Forward to current frame. */
+	pck_desc += pbuf->frames;
+	pck_desc->frm_ofs =
+	    (pbuf->phy_addr - shm_base_addr) + pbuf->frm_ofs;
+	pck_desc->frm_len = frmlen;
+
+	/* Terminate packet descriptor area. */
+	pck_desc++;
+	pck_desc->frm_ofs = 0;
+
+	/* Update buffer parameters. */
+	pbuf->frames++;
+	pbuf->frm_ofs += frmlen + (frmlen % 32);
+
+	spin_lock(&lock);
+	/* Assign buffer as pending. */
+	list_add_tail(&pbuf->list, &pshm->tx_pend_list);
+	spin_unlock(&lock);
+
+	/* Schedule signaling work queue. */
+	(void) queue_work(pshm->sig_work_queue, &pshm->sig_work);
+
+	/* The packet is sent. As we have come to the end of the line we need
+	 * to free the packet. */
+	f.cfpkt_destroy(cfpkt);
+
+	return ESUCCESS;
+}
+
+int shm_phy_tx(layer_t *layr, transmt_info *info, cfpkt_t *cfpkt)
+{
+	shm_layer_t *pshm;
+	int result;
+
+	/* TODO: We need a mutex here if this function can be called from
+	 * different contexts. */
+
+	pshm = container_of(layr, shm_layer_t, shm_phy);
+
+	/* First try to append the frame. */
+	result = shm_send_pkt(pshm, cfpkt, true);
+	if (!result)
+		return result;
+
+	/* Try a new buffer. */
+	result = shm_send_pkt(pshm, cfpkt, false);
+
+	return result;
+}
+
+static int __init phyif_shm_init(void)
+{
+	int result = -1;
+	int i, j;
+
+	/* Initialize the shared memory instances. */
+	for (i = 0; i < SHM_INSTANCES; i++) {
+		/* Initialize structures in a clean state. */
+		memset(&shm_layer[i], 0, sizeof(shm_layer[i]));
+
+		/* Fill in some information about our PHY. */
+		shm_layer[i].shm_phy.transmit = shm_phy_tx;
+		shm_layer[i].shm_phy.receive = NULL;
+		shm_layer[i].shm_phy.ctrlcmd = shm_phy_fctrl;
+
+		/* TODO: Instance number should be appended. */
+		sprintf(shm_layer[i].cfg_name, "%s%d", mbxcfg_name, i);
+		sprintf(shm_layer[i].mbx_name, "%s%d", mbxifc_name, i);
+
+		/* Initialize queues. */
+		INIT_LIST_HEAD(&(shm_layer[i].tx_empty_list));
+		INIT_LIST_HEAD(&(shm_layer[i].rx_empty_list));
+		INIT_LIST_HEAD(&(shm_layer[i].tx_pend_list));
+		INIT_LIST_HEAD(&(shm_layer[i].rx_pend_list));
+		INIT_LIST_HEAD(&(shm_layer[i].tx_full_list));
+		INIT_LIST_HEAD(&(shm_layer[i].rx_full_list));
+
+		INIT_WORK(&shm_layer[i].sig_work, phyif_shm_sig_work_func);
+		INIT_WORK(&shm_layer[i].rx_work, phyif_shm_rx_work_func);
+		INIT_WORK(&shm_layer[i].flow_work, phyif_shm_flow_work_func);
+
+		/* Create the RX work thread.
+		 * TODO: Instance number should be appended. */
+		shm_layer[i].rx_work_queue =
+		    create_singlethread_workqueue("phyif_shm_rx");
+
+		/* Create the signaling work thread.
+		 * TODO: Instance number should be appended. */
+
+		shm_layer[i].sig_work_queue =
+		    create_singlethread_workqueue("phyif_shm_sig");
+
+		/* Create the flow re-enable work thread.
+		 * TODO: Instance number should be appended. */
+		shm_layer[i].flow_work_queue =
+			create_singlethread_workqueue("phyif_shm_flow");
+
+		init_waitqueue_head(&(shm_layer[i].mbx_space_wq));
+		shm_layer[i].tx_empty_available = 1;
+
+		/* Connect to the shared memory configuration module. */
+		/*shm_layer[i].cfg_ifc = cfgifc_get(shm_layer[i].cfg_name);*/
+
+		/* Initialize the shared memory transmit buffer queues. */
+		for (j = 0; j < shm_nr_tx_buf; j++) {
+			shm_buf_t *tx_buf =
+			    kmalloc(sizeof(shm_buf_t), GFP_KERNEL);
+			tx_buf->index = j;
+			tx_buf->len = shm_tx_buf_len;
+			if ((i % 2) == 0) {
+				tx_buf->phy_addr =
+				    shm_tx_addr + (shm_tx_buf_len * j);
+			} else {
+				tx_buf->phy_addr =
+				    shm_rx_addr + (shm_tx_buf_len * j);
+			}
+			tx_buf->desc_ptr =
+			    ioremap(tx_buf->phy_addr, shm_tx_buf_len);
+			tx_buf->frames = 0;
+			tx_buf->frm_ofs = SHM_CAIF_FRM_OFS;
+			list_add_tail(&tx_buf->list,
+				      &shm_layer[i].tx_empty_list);
+		}
+
+		/* Initialize the shared memory receive buffer queues. */
+		for (j = 0; j < shm_nr_rx_buf; j++) {
+			shm_buf_t *rx_buf =
+			    kmalloc(sizeof(shm_buf_t), GFP_KERNEL);
+			rx_buf->index = j;
+			rx_buf->len = shm_rx_buf_len;
+			if ((i % 2) == 0) {
+				rx_buf->phy_addr =
+				    shm_rx_addr + (shm_rx_buf_len * j);
+			} else {
+				rx_buf->phy_addr =
+				    shm_tx_addr + (shm_rx_buf_len * j);
+			}
+			rx_buf->desc_ptr =
+			    ioremap(rx_buf->phy_addr, shm_rx_buf_len);
+			list_add_tail(&rx_buf->list,
+				      &shm_layer[i].rx_empty_list);
+		}
+
+		/* Connect to the shared memory mailbox module. */
+		shm_layer[i].mbx_ifc = mbxifc_get(shm_layer[i].mbx_name);
+		if (!shm_layer[i].mbx_ifc) {
+			printk(KERN_WARNING
+			       "phyif_shm_init: can't find mailbox: %s.\n",
+			       shm_layer[i].mbx_name);
+			/* CLEANUP !!! */
+			return CFGLU_ENXIO;
+		}
+
+		/* Fill in some info about ourselves. */
+		shm_layer[i].mbx_client.cb = phyif_shm_mbx_msg_cb;
+		shm_layer[i].mbx_client.priv = (void *) &shm_layer[i];
+
+		shm_layer[i].mbx_ifc->init(&shm_layer[i].mbx_client,
+					   shm_layer[i].mbx_ifc->priv);
+
+		if ((i % 2) == 0) {
+			/* Register physical interface. */
+			result =
+			    caifdev_phy_register(&shm_layer[i].shm_phy,
+						 CFPHYTYPE_SHM,
+						 CFPHYPREF_UNSPECIFIED);
+		} else {
+			/* Register loop interface. */
+			result =
+			    caifdev_phy_loop_register(&shm_layer
+						      [i].shm_phy,
+						      CFPHYTYPE_SHM);
+		}
+
+		if (result < 0) {
+			printk(KERN_WARNING
+			       "phyif_shm_init: err: %d, "
+			       "can't register phy layer.\n",
+			       result);
+			/* CLEANUP !!! */
+		}
+
+	}
+
+	return result;
+}
+
+static void phyif_shm_exit(void)
+{
+	shm_buf_t *pbuf;
+	uint8 i = 0;
+	for (i = 0; i < SHM_INSTANCES; i++) {
+
+		/* unregister callbacks from mailbox interface */
+		shm_layer[i].mbx_client.cb = NULL;
+
+		/* TODO: wait for completetion or timeout */
+		while (!(list_empty(&shm_layer[i].tx_pend_list))) {
+			pbuf =
+			    list_entry(shm_layer[i].tx_pend_list.next,
+			       shm_buf_t, list);
+
+			kfree(pbuf);
+			list_del(&pbuf->list);
+		}
+
+		/* TODO: wait for completetion or timeout */
+		while (!(list_empty(&shm_layer[i].tx_full_list))) {
+			pbuf =
+			    list_entry(shm_layer[i].tx_full_list.next,
+				       shm_buf_t, list);
+			kfree(pbuf);
+			list_del(&pbuf->list);
+		}
+
+		while (!(list_empty(&shm_layer[i].tx_empty_list))) {
+			pbuf =
+			    list_entry(shm_layer[i].tx_empty_list.next,
+			       shm_buf_t, list);
+			kfree(pbuf);
+			list_del(&pbuf->list);
+		}
+
+		/* TODO: wait for completetion or timeout */
+		while (!(list_empty(&shm_layer[i].rx_full_list))) {
+			pbuf =
+			    list_entry(shm_layer[i].tx_full_list.next,
+			       shm_buf_t, list);
+			kfree(pbuf);
+			list_del(&pbuf->list);
+		}
+
+		/* TODO: wait for completetion or timeout */
+		while (!(list_empty(&shm_layer[i].rx_pend_list))) {
+			pbuf =
+			    list_entry(shm_layer[i].tx_pend_list.next,
+				       shm_buf_t, list);
+			kfree(pbuf);
+			list_del(&pbuf->list);
+		}
+
+		while (!(list_empty(&shm_layer[i].rx_empty_list))) {
+			pbuf =
+			    list_entry(shm_layer[i].rx_empty_list.next,
+				       shm_buf_t, list);
+			kfree(pbuf);
+			list_del(&pbuf->list);
+		}
+	}
+
+	/* destroy work queues */
+	destroy_workqueue(shm_layer[i].rx_work_queue);
+	destroy_workqueue(shm_layer[i].sig_work_queue);
+}
+
+module_init(phyif_shm_init);
+module_exit(phyif_shm_exit);
diff --git a/drivers/net/caif/shm.h b/drivers/net/caif/shm.h
new file mode 100644
index 0000000..d117b0a
--- /dev/null
+++ b/drivers/net/caif/shm.h
@@ -0,0 +1,95 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+#ifndef SHM_H_
+#define SHM_H_
+
+#include <linux/list.h>
+/*#include <linux/init.h>
+#include <linux/workqueue.h>*/
+#include "caif_layer.h"
+
+#define ESUCCESS    0
+
+typedef int (*mbxifc_cb_t) (u16 mbx_msg, void *priv);
+
+/*FIXME:why is the client here??*/
+/* Shared memory mailbox client structure. */
+typedef struct _shm_mbxclient_t {
+	mbxifc_cb_t cb;
+	void *priv;
+} shm_mbxclient_t;
+
+typedef int (*mbxifc_init_t) (shm_mbxclient_t *mbx_client, void *priv);
+
+typedef int (*mbxifc_send_t) (u16 mbx_msg, void *priv);
+
+/* Shared memory mailbox interface structure. */
+typedef struct _shm_mbxifc_t {
+	mbxifc_init_t init;
+	mbxifc_send_t send_msg;
+	char name[16];
+	void *priv;
+	shm_mbxclient_t *client;
+	struct list_head list;
+} shm_mbxifc_t;
+
+int mbxifc_register(shm_mbxifc_t *client);
+
+int mbxifc_send(u16 mbx_msg, void *priv);
+shm_mbxifc_t *mbxifc_get(unsigned char *name);
+void mbxifc_put(shm_mbxifc_t *mbx_ifc);
+
+/* emardan: Use B380 setup for the first CAIF channel.*/
+/* TODO: This needs to go into a shared memory interface. */
+static int shm_base_addr = 0x81F00000;
+module_param(shm_base_addr, int, S_IRUGO);
+MODULE_PARM_DESC(shm_base_addr,
+		 "Physical base address of the shared memory area");
+
+static int shm_tx_addr = 0x81F00000;
+module_param(shm_tx_addr, int, S_IRUGO);
+MODULE_PARM_DESC(shm_tx_addr, "Physical start address for transmission area");
+
+static int shm_rx_addr = 0x81F0C000;
+module_param(shm_rx_addr, int, S_IRUGO);
+MODULE_PARM_DESC(shm_rx_addr, "Physical start address for reception area");
+
+static int shm_nr_tx_buf = 6;
+module_param(shm_nr_tx_buf, int, S_IRUGO);
+MODULE_PARM_DESC(shm_nr_tx_buf, "number of transmit buffers");
+
+static int shm_nr_rx_buf = 6;
+module_param(shm_nr_rx_buf, int, S_IRUGO);
+MODULE_PARM_DESC(shm_nr_rx_buf, "number of receive buffers");
+
+static int shm_tx_buf_len = 0x2000;
+module_param(shm_tx_buf_len, int, S_IRUGO);
+MODULE_PARM_DESC(shm_tx_buf_len, "size of transmit buffers");
+
+static int shm_rx_buf_len = 0x2000;
+module_param(shm_rx_buf_len, int, S_IRUGO);
+MODULE_PARM_DESC(shm_rx_buf_len, "size of receive buffers");
+
+/* Shared memory interface structure. */
+typedef struct _shm_cfgifc_t {
+	int base_addr;
+	int tx_addr;
+	int rx_addr;
+	int nr_tx_buf;
+	int nr_rx_buf;
+	int tx_buf_len;
+	int rx_buf_len;
+	char name[16];
+	struct list_head list;
+} shm_cfgifc_t;
+
+shm_cfgifc_t *cfgifc_get(unsigned char *name);
+
+#endif				/* SHM_H_ */
diff --git a/drivers/net/caif/shm_cfgifc.c b/drivers/net/caif/shm_cfgifc.c
new file mode 100644
index 0000000..bf00ce0
--- /dev/null
+++ b/drivers/net/caif/shm_cfgifc.c
@@ -0,0 +1,60 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+/* Standard includes. */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+
+#include "shm.h"
+
+MODULE_LICENSE("GPL");
+
+static struct list_head cfgifc_list;
+
+void cfgifc_exit_module(void)
+{
+
+}
+
+int cfgifc_init_module(void)
+{
+	return -ENODEV;
+}
+
+int cfgifc_register(shm_cfgifc_t *mbx_ifc)
+{
+	return 0;
+}
+EXPORT_SYMBOL(cfgifc_register);
+
+shm_cfgifc_t *cfgifc_get(unsigned char *name)
+{
+	/* Hook up the adaptation layer. TODO: Make phy_type dynamic. */
+	cfcnfg_add_adapt_layer(caifdev.cfg, linktype, connid,
+			       CFPHYTYPE_SERIAL, adap_layer);
+
+	return NULL;
+}
+EXPORT_SYMBOL(cfgifc_get);
+
+void cfgifc_put(shm_cfgifc_t *mbx_ifc)
+{
+	/* Hook up the adaptation layer. TODO: Make phy_type dynamic. */
+	cfcnfg_add_adapt_layer(caifdev.cfg, linktype, connid,
+			       CFPHYTYPE_SERIAL, adap_layer);
+
+	return 0;
+}
+EXPORT_SYMBOL(cfgifc_put);
+
+
+module_init(cfgifc_init_module);
+module_exit(cfgifc_exit_module);
diff --git a/drivers/net/caif/shm_mbxifc.c b/drivers/net/caif/shm_mbxifc.c
new file mode 100644
index 0000000..f108799
--- /dev/null
+++ b/drivers/net/caif/shm_mbxifc.c
@@ -0,0 +1,98 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+/* Standard includes. */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+
+#include "shm.h"
+
+MODULE_LICENSE("GPL");
+
+static struct list_head mbxifc_list;
+
+void mbxifc_exit_module(void)
+{
+
+}
+
+int mbxifc_init_module(void)
+{
+	INIT_LIST_HEAD(&mbxifc_list);
+
+	return ESUCCESS;
+}
+
+int mbxifc_register(shm_mbxifc_t *mbxifc)
+{
+	if (!mbxifc)
+		return -EINVAL;
+
+	list_add_tail(&mbxifc->list, &mbxifc_list);
+	printk(KERN_WARNING
+	       "mbxifc_register: mailbox: %s at 0x%p added.\n",
+	       mbxifc->name, mbxifc);
+
+	return ESUCCESS;
+}
+EXPORT_SYMBOL(mbxifc_register);
+
+int mbxifc_unregister(shm_mbxifc_t *mbx_ifc)
+{
+	shm_mbxifc_t *mbxifcreg;
+
+	while (!(list_empty(&mbxifc_list))) {
+		mbxifcreg = list_entry(mbxifc_list.next, shm_mbxifc_t, list);
+		if (mbxifcreg == mbx_ifc) {
+			list_del(&mbxifcreg->list);
+			break;
+		}
+	}
+
+	return ESUCCESS;
+}
+EXPORT_SYMBOL(mbxifc_unregister);
+
+shm_mbxifc_t *mbxifc_get(unsigned char *name)
+{
+	shm_mbxifc_t *mbxifc;
+	struct list_head *pos;
+	list_for_each(pos, &mbxifc_list) {
+		mbxifc = list_entry(pos, shm_mbxifc_t, list);
+		if (strcmp(mbxifc->name, name) == 0) {
+			list_del(&mbxifc->list);
+			printk(KERN_WARNING
+			       "mbxifc_get: mailbox: %s at 0x%p found.\n",
+			       mbxifc->name, mbxifc);
+			return mbxifc;
+		}
+	}
+
+	printk(KERN_WARNING "mbxifc_get: no mailbox: %s found.\n", name);
+
+	return NULL;
+}
+EXPORT_SYMBOL(mbxifc_get);
+
+void mbxifc_put(shm_mbxifc_t *mbx_ifc)
+{
+	if (!mbx_ifc)
+		return;
+
+	list_add_tail(&mbx_ifc->list, &mbxifc_list);
+
+	return;
+}
+EXPORT_SYMBOL(mbxifc_put);
+
+
+module_init(mbxifc_init_module);
+module_exit(mbxifc_exit_module);
diff --git a/drivers/net/caif/shm_smbx.c b/drivers/net/caif/shm_smbx.c
new file mode 100644
index 0000000..57770d4
--- /dev/null
+++ b/drivers/net/caif/shm_smbx.c
@@ -0,0 +1,81 @@ 
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+/* Very simple simulated mailbox interface supporting
+ * multiple mailbox instances. */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include "shm.h"
+
+MODULE_LICENSE("GPL");
+
+#define MBX_NR_OF_INSTANCES	2
+#define MBX_SMBX_NAME		"cfmbx"
+
+typedef struct _shm_smbx_t {
+	shm_mbxifc_t local;
+	shm_mbxifc_t *peer;
+} shm_smbx_t;
+
+static shm_smbx_t shm_smbx[MBX_NR_OF_INSTANCES];
+
+static int smbx_ifc_init(shm_mbxclient_t *mbx_client, void *priv)
+{
+	shm_smbx_t *mbx = (shm_smbx_t *) priv;
+
+	mbx->local.client = mbx_client;
+
+	return 0;
+}
+
+static int smbx_ifc_send_msg(u16 mbx_msg, void *priv)
+{
+	shm_smbx_t *mbx = (shm_smbx_t *) priv;
+
+	mbx->peer->client->cb(mbx_msg, mbx->peer->client->priv);
+
+	return 0;
+
+}
+
+static int __init shm_smbx_init(void)
+{
+	int i;
+
+	for (i = 0; i < MBX_NR_OF_INSTANCES; i++) {
+		/* Set up the mailbox interface. */
+		shm_smbx[i].local.init = smbx_ifc_init;
+		shm_smbx[i].local.send_msg = smbx_ifc_send_msg;
+		sprintf(shm_smbx[i].local.name, "%s%d", MBX_SMBX_NAME, i);
+		shm_smbx[i].local.priv = &shm_smbx[i];
+
+		/* Set up the correct peer.
+		 * (0 is connected to one and so forth). */
+		if (i % 2)
+			shm_smbx[i].peer = &shm_smbx[i - 1].local;
+		else
+			shm_smbx[i].peer = &shm_smbx[i + 1].local;
+
+
+		mbxifc_register(&(shm_smbx[i].local));
+	}
+
+	return 0;
+}
+
+static void shm_smbx_exit(void)
+{
+	/* Nothing to do. */
+}
+
+module_init(shm_smbx_init);
+module_exit(shm_smbx_exit);