netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] [CAIF-RFC 0/8-v2] CAIF Protocol Stack
@ 2009-10-09 13:39 sjur.brandeland
  2009-10-09 13:39 ` [PATCH] [CAIF-RFC 1/8-v2] " sjur.brandeland
  2009-10-12  9:41 ` [PATCH] [CAIF-RFC 0/8-v2] " David Miller
  0 siblings, 2 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev, netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

This is the second version of the CAIF patch set.
The patch set is compiled on 386 for 2.6.31.
All feedback is apreciated.

Change log:
* Minor documentation updates
* Character device chnl_chr.c now supports non-blocking open/close.
* Net device chnl_net.c now support multiple instances.
* Cleanup of create_channel.cnf
* Spelling issues in Kconfig files
* Compilation problems in chardevconfig 
* Makefile problems compiling Net and Char dev
* Removed obsolete chnl_tty.c
* Removed shared memory physical interface
* Remove #ifdef CAIF_USE_SKB from caif_layer.h
* Changed #include statements all over.


BR/Sjur Brændeland

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

* [PATCH] [CAIF-RFC 1/8-v2] CAIF Protocol Stack
  2009-10-09 13:39 [PATCH] [CAIF-RFC 0/8-v2] CAIF Protocol Stack sjur.brandeland
@ 2009-10-09 13:39 ` sjur.brandeland
  2009-10-09 13:39   ` [PATCH] [CAIF-RFC 2/8-v2] " sjur.brandeland
  2009-10-12  8:08   ` [PATCH] [CAIF-RFC 1/8-v2] " Stefano Babic
  2009-10-12  9:41 ` [PATCH] [CAIF-RFC 0/8-v2] " David Miller
  1 sibling, 2 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: I305056f116a11c31265f65ac0fe285e2b655dd54
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 include/linux/caif/caif_config.h |  203 ++++++++++++++++++++++++++++++++++++++
 include/linux/caif/caif_ioctl.h  |  113 +++++++++++++++++++++
 2 files changed, 316 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/caif/caif_config.h
 create mode 100644 include/linux/caif/caif_ioctl.h

diff --git a/include/linux/caif/caif_config.h b/include/linux/caif/caif_config.h
new file mode 100644
index 0000000..6ea934b
--- /dev/null
+++ b/include/linux/caif/caif_config.h
@@ -0,0 +1,203 @@
+/*
+ *	Copyright (C) ST-Ericsson AB 2009
+ *
+ *	CAIF Channel Configuration definitions.
+ *
+ *	Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+ *
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#ifndef CAIF_CONFIG_H_
+#define CAIF_CONFIG_H_
+
+/**
+ * enum caif_phy_preference -	Types of Physical HW Interfaces
+ *				towards modem defined in CAIF Stack,
+ * @CAIF_PHYPREF_UNSPECIFIED:	Default Physical Interface
+ * @CAIF_PHYPREF_LOW_LAT:	Default Physical Interface for Low Latency
+ *				Traffic
+ * @CAIF_PHYPREF_HIGH_BW:	Default Physical Interface for High Bandwidth
+ *				Traffic
+ * @_CAIF_PHYPREF_LOOP:		TEST Loop-back Interface Simulating Acc side
+ *				responses
+ * @_CAIF_PHYPREF_RAW_LOOP:	TEST ONLY Raw loopback interface
+ *
+ * For Client convenience to special types are defined:
+ * CAIF_PHYPREF_LOW_LAT is the preferred low latency physical link.
+ * Typically used for "control" purposes.
+ * CAIF_PHYPREF_HIGH_BW is the preferred high bandwidth physical link.
+ * Typically used for "payload" purposes.
+ *
+ */
+enum caif_phy_preference {
+	CAIF_PHYPREF_UNSPECIFIED	= 0x00,
+	CAIF_PHYPREF_LOW_LAT		= 0xd0,
+	CAIF_PHYPREF_HIGH_BW		= 0xe0,
+	_CAIF_PHYPREF_LOOP		= 0x70,
+	_CAIF_PHYPREF_RAW_LOOP		= 0x80
+};
+
+
+/*!
+ * define CAIF Channel Priority.
+ * Used when setting up a Channel to specify the
+ * priority level of the channel.
+ */
+
+#define CAIF_PRIO_UNSPCEIFIED  0x0
+#define CAIF_PRIO_MIN	       0x01	/*! Minimum Priority Level */
+#define CAIF_PRIO_LOW	       0x04	/*!< Suggested Priority Level for
+					 *   Low Priority Channel */
+#define CAIF_PRIO_NORMAL       0x0f	/*!< Suggested Normal/Default
+					 *   priority Level */
+#define CAIF_PRIO_HIGH	       0x14	/*!< Suggested High Priority Level */
+#define CAIF_PRIO_MAX	       0x1F	/*!< Max Priority for Channel
+					   (do not use)
+					 */
+
+/**
+ * enum caif_channel_type  Types of CAIF Channel type defined in CAIF Stack.
+ * @CAIF_CHTY_AT:		Classical AT
+ * @CAIF_CHTY_AT_CTRL:		AT Control only
+ * @CAIF_CHTY_AT_PAIRED:	Paired control and data
+ * @CAIF_CHTY_DATAGRAM:		Datagram, Requires: connection_id
+ * @CAIF_CHTY_DATAGRAM_LOOP:	Datagram Loopback (testing purposes only)
+ * @CAIF_CHTY_VIDEO:		Video Channel
+ * @CAIF_CHTY_DEBUG:		Debug Service (Debug Server and
+ *					       Interactive Debug)
+ * @CAIF_CHTY_DEBUG_TRACE:	Debug Server only
+ * @CAIF_CHTY_DEBUG_INTERACT:	Debug Interactive
+ * @CAIF_CHTY_RFM:		RFM Service. Params: connection_id, volume
+ * @CAIF_CHTY_UTILITY:		Utility (Psock) Service.
+ *				Params: fifo_kb,fifo_pkt, name, psock_param
+ * @CAIF_CHTY_RAW:		DO NOT USE. This is for testing only
+ *
+ * This is used for Channel Configuration specifying the type of channel.
+ */
+
+enum caif_channel_type {
+	CAIF_CHTY_AT,
+	CAIF_CHTY_AT_CTRL,
+	CAIF_CHTY_AT_PAIRED,
+	CAIF_CHTY_DATAGRAM,
+	CAIF_CHTY_DATAGRAM_LOOP,
+	CAIF_CHTY_VIDEO,
+	CAIF_CHTY_DEBUG,
+	CAIF_CHTY_DEBUG_TRACE,
+	CAIF_CHTY_DEBUG_INTERACT,
+	CAIF_CHTY_RFM,
+	CAIF_CHTY_UTILITY,
+	CAIF_CHTY_RAW
+};
+
+/**
+ *struct caif_channel_config This structures is used for configuring
+ *			     CAIF Channels.
+ * @name: Mandatory:	     Nickname for this device
+ * @type:		     Mandatory Define the type of caif service
+ * @priority:		     Mandatory Value between  CAIF_PRIO_MIN and
+ *			     CAIF_PRIO_MAX,
+ *			     CAIF_PRIO_LOW, CAIF_PRIO_NORMAL, CAIF_PRIO_HIGH
+ *			     are suggested values.
+ * @phy_pref:		     Either: Specify type of physical interface to use.
+ * @phy_name:		     Or: Specify identity of the physical interface.
+ *
+ * @u:			     Union of Channel Type Specific configuration
+ *			     parameters
+ *
+ * @u.dgm:		     CAIF_CHTYPE_DATAGRAM
+ * @u.dgm.connection_id:     Mandatory Connection ID must be specified.
+ *
+ * @u.video:		     CAIF_CHTYPE_VIDEO
+ * @u.video.connection_id:   Mandatory Connection ID must be specified.
+ *
+ * @u.rfm		     CAIF_CHTYPE_RFM
+ * @u.rfm.connection_id:     Mandatory Connection ID must be specified.
+ * @u.rfm.volume:	     Mandatory Volume to mount.
+ *
+ * @u.utility:		     CAIF_CHTYPE_UTILITY
+ * @u.utility.fifosize_kb:   Psock: FIFO size in KB
+ * @u.utility.fifosize_bufs: Psock: # signal buffers
+ * @u.utility.name:	     Psock: Name of service
+ * @u.utility.params:	     Psock: Channel Config Parameters
+ * @u.utility.paramlen:	     Psock: Length of Channel Config Parameters
+ *
+ *
+ * It holds configuration parameters for setting up all devined CAIF
+ * Channel types.
+ * The four first fields are mandatory, then Physical Device can be specified
+ * either by name
+ * or by prefered characteristics.
+ * The rest of the configuration fields are hold in a union for each
+ * channel type and are channel type specific.
+ * \b Documentation see STE Doc No: 155 19-CRH 109 913.
+ */
+
+struct caif_channel_config {
+       /* Mandatory: Nickname for this device */
+	char name[16];
+	/* Mandatory: Define the type of caif service */
+	enum caif_channel_type type;
+	/** Mandatory: Mandatory - Value between
+	  * CAIF_PRIO_MIN and CAIF_PRIO_MAX, CAIF_PRIO_LOW, CAIF_PRIO_NORMAL,
+	  *  CAIF_PRIO_HIGH are suggested values. */
+	unsigned priority;
+
+	/** Either: Specify type of physical interface to use. */
+	enum caif_phy_preference phy_pref;
+	/** Or: Specify identity of the physical interface. */
+	char phy_name[16];
+
+	/** Union of Channel Type Specific configuration parameters
+	* 'switched' by attribute type */
+	union {
+		/* CAIF_CHTYPE_DATAGRAM */
+		struct {
+		       /**  Mandatory Connection ID  must be specified. */
+			unsigned connection_id;
+		} dgm;
+		/* CAIF_CHTYPE_VIDEO */
+		struct {
+			/** Datagram:  Mandatory Connection ID Must be
+			 *  specified. */
+			unsigned connection_id;
+		} video;
+		/* CAIF_CHTYPE_RFM */
+		struct {
+			/** RFM: Mandatory Connection ID. */
+			unsigned connection_id;
+			/** RFM: Mandatory Volume to mount. */
+			char volume[20];
+		} rfm;
+		/* CAIF_CHTYPE_UTILITY */
+		struct {
+/** Psock: FIFO size in KB */
+			unsigned fifosize_kb;
+/** Psock: # signal buffers */
+			unsigned fifosize_bufs;
+/** Psock: Name of service */
+			char name[16];
+/** Psock: Channel Config Parameters> */
+			unsigned char params[256];
+/** Psock: Length of Channel Config Parameters */
+			int paramlen;
+		} utility;
+
+
+		/* Raw Data configuration: DO NOT USE,
+		 * applies for testing only */
+
+		struct raw {
+			unsigned channeltype;
+			unsigned char endpoint:2;
+			unsigned char subtype:2;
+			unsigned char serviceconfig[512];
+			unsigned int service_length;
+		} _raw;
+	} u;
+
+};
+
+#endif				/* CAIF_CONFIG_H_ */
diff --git a/include/linux/caif/caif_ioctl.h b/include/linux/caif/caif_ioctl.h
new file mode 100644
index 0000000..421a4b2
--- /dev/null
+++ b/include/linux/caif/caif_ioctl.h
@@ -0,0 +1,113 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+#ifndef CAIF_IOCTL_H_
+#define CAIF_IOCTL_H_
+#include <linux/caif/caif_config.h>
+
+
+/*!\page  caif_ioctl.h
+ * This file defines the management interface to CAIF.
+ * It defines how CAIF Channels are configured and become visible in Linux
+ * file system under "/dev/caifconfig".
+ *
+ *\b Example - creating a new AT character device:
+ * \code
+   fd = open("/dev/caifconfig",..);
+   struct caif_channel_create_action at_config = {
+	 .name = "cnhl2",
+	 .config = {
+	    .channel = CAIF_CHTY_AT,
+	    .phy_ref = CAIF_PHY_LOW_LAT,
+	    .priority = CAIF_PRIO_HIGH
+	 }};
+   ioctl(fd, CAIF_IOC_CONFIG_DEVICE,&at_config);
+   close(fd);
+ * \endcode
+ * This will cause a new AT channel to be available in at "/dev/chnl2".
+ * This CAIF channel can then be connected by using \ref open.
+ *
+*/
+
+/*! \addtogroup caif_ioctl
+ *  Additional documentation for group `caif_config.h'
+ *  @{
+ */
+
+
+
+/* Use 'g' as magic number. 'g' is the first free letter in
+ * Documentation/ioctl-number.txt*/
+#define CAIF_IOC_MAGIC 'g'
+#define DEVICE_NAME_LEN 16
+
+/* Specifies the type of device to create NET device or CHAR device*/
+enum caif_dev_type {
+	CAIF_DEV_CHR = 1,
+	CAIF_DEV_NET = 2
+};
+
+
+/** Used for identifying devices, PHY interfaces etc*/
+struct caif_device_name {
+	char name[DEVICE_NAME_LEN];	/*!< Device name */
+	enum caif_dev_type devtype;	/*!< Device type */
+};
+
+
+/**
+ * CAIF ACTION for \ref CAIF_ACT_CHANNEL_CONFIG.
+ * This structure is used to configure a new CAIF Channel and
+ * create the corresponding character device.
+ */
+struct caif_channel_create_action {
+	/** \b in  CAIF Configuration Request */
+	struct caif_channel_config config;
+	/** \b in/out Device name returned from ACTION */
+	struct caif_device_name name;
+	/** \b out Major device id */
+	int major;
+	/** \b out Minor device id */
+	int minor;
+};
+
+/**
+ * union caif_action
+ * This union is used to configure a new CAIF Channel and
+ */
+
+union caif_action {
+	struct caif_device_name delete_channel;
+	struct caif_channel_create_action create_channel;
+};
+
+
+/**
+ * CAIF IOCTL for \ref CAIF_IOC_CHANNEL_CONFIG.
+ * This structure is used to configure a new CAIF Channel and
+ * create the corresponding character device.
+ */
+
+/** Create and Configure a new CAIF device.
+ * Note that the device is not implicitly connected. */
+#define CAIF_IOC_CONFIG_DEVICE		_IOWR(CAIF_IOC_MAGIC, 1,\
+struct caif_channel_create_action)
+
+/** Remove a CAIF device. Requires the device to be previously disconnected. */
+#define CAIF_IOC_REMOVE_DEVICE		_IOWR(CAIF_IOC_MAGIC, 2,\
+		struct caif_device_name)
+#define CAIF__IOC_MAXNR				9
+/*! @} */
+
+#endif				/* CAIF_IOCTL_H_ */
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 2/8-v2] CAIF Protocol Stack
  2009-10-09 13:39 ` [PATCH] [CAIF-RFC 1/8-v2] " sjur.brandeland
@ 2009-10-09 13:39   ` sjur.brandeland
  2009-10-09 13:39     ` [PATCH] [CAIF-RFC 3/8-v2] " sjur.brandeland
  2009-10-12  9:28     ` [PATCH] [CAIF-RFC 2/8-v2] " Stefano Babic
  2009-10-12  8:08   ` [PATCH] [CAIF-RFC 1/8-v2] " Stefano Babic
  1 sibling, 2 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: Ic66e718f40015c433b1464d0ea3af96431a407a8
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 include/net/caif/generic/caif_layer.h |  378 +++++++++++++++++++++++++++++++++
 include/net/caif/generic/cfcnfg.h     |  223 +++++++++++++++++++
 include/net/caif/generic/cfctrl.h     |  139 ++++++++++++
 include/net/caif/generic/cffrml.h     |   29 +++
 include/net/caif/generic/cfglue.h     |  206 ++++++++++++++++++
 include/net/caif/generic/cfloopcfg.h  |   28 +++
 include/net/caif/generic/cflst.h      |   27 +++
 include/net/caif/generic/cfmsll.h     |   22 ++
 include/net/caif/generic/cfmuxl.h     |   30 +++
 include/net/caif/generic/cfpkt.h      |  246 +++++++++++++++++++++
 include/net/caif/generic/cfserl.h     |   22 ++
 include/net/caif/generic/cfshml.h     |   21 ++
 include/net/caif/generic/cfspil.h     |   80 +++++++
 include/net/caif/generic/cfsrvl.h     |   48 ++++
 include/net/caif/generic/fcs.h        |   22 ++
 15 files changed, 1521 insertions(+), 0 deletions(-)
 create mode 100644 include/net/caif/generic/caif_layer.h
 create mode 100644 include/net/caif/generic/cfcnfg.h
 create mode 100644 include/net/caif/generic/cfctrl.h
 create mode 100644 include/net/caif/generic/cffrml.h
 create mode 100644 include/net/caif/generic/cfglue.h
 create mode 100644 include/net/caif/generic/cfloopcfg.h
 create mode 100644 include/net/caif/generic/cflst.h
 create mode 100644 include/net/caif/generic/cfmsll.h
 create mode 100644 include/net/caif/generic/cfmuxl.h
 create mode 100644 include/net/caif/generic/cfpkt.h
 create mode 100644 include/net/caif/generic/cfserl.h
 create mode 100644 include/net/caif/generic/cfshml.h
 create mode 100644 include/net/caif/generic/cfspil.h
 create mode 100644 include/net/caif/generic/cfsrvl.h
 create mode 100644 include/net/caif/generic/fcs.h

diff --git a/include/net/caif/generic/caif_layer.h b/include/net/caif/generic/caif_layer.h
new file mode 100644
index 0000000..0918f6a
--- /dev/null
+++ b/include/net/caif/generic/caif_layer.h
@@ -0,0 +1,378 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Braendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+#ifndef CAIF_LAYER_H_
+#define CAIF_LAYER_H_
+
+#include <net/caif/generic/cfglue.h>
+/* Forward Declaration */
+struct _layer_t;
+struct _cfpkt_t;
+struct _cfpktq_t;
+struct _transmt_info;
+struct _caif_packet_funcs_t;
+typedef struct _cfpktq_t cfpktq_t;
+/* Type definitions*/
+typedef struct _transmt_info transmt_info;
+
+typedef struct _layer_t layer_t;
+typedef struct _caif_packet_funcs_t caif_packet_funcs_t;
+typedef struct _cfpkt_t cfpkt_t;
+
+#define CAIF_MAX_FRAMESIZE 4096
+#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64)
+#define CAIF_NEEDED_HEADROOM (10)
+#define CAIF_NEEDED_TAILROOM (2)
+
+/*! \addtogroup GenCaifExternal
+ *  Additional documentation for group `GenCaifExternal'
+ *  @{
+ */
+
+
+/** CAIF Control Signaling.
+ *  These commands are sent upwards in the CAIF stack. They are used for
+ *  Signaling originating from Modem.
+ *  These are either responses (*_RSP) or events (*_IND).
+
+ */
+typedef enum _caif_ctrlcmd_t {
+	/** Flow Control is OFF, transmit function should stop sending data */
+	CAIF_CTRLCMD_FLOW_OFF_IND = 0,
+	/** Flow Control is ON, transmit function can start sending data */
+	CAIF_CTRLCMD_FLOW_ON_IND = 1,
+	/** Remote end CCPU has decided to close down channel */
+	CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND = 5,
+	/** Called initially when the layer below has finished initialization */
+	CAIF_CTRLCMD_INIT_RSP = 3,
+	/** Called when de-initialization is complete */
+	CAIF_CTRLCMD_DEINIT_RSP = 4,
+	/** Called if initialization failes */
+	CAIF_CTRLCMD_INIT_FAIL_RSP = 6,
+	/** Note: Only used internally in GenCaif.
+	 * Called if physical interface cannot send more packets */
+	_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND = 7,
+	/** Note: Only used internally in GenCaif.
+	 * Called if physical interface is able to send packets again */
+	_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND = 8
+} caif_ctrlcmd_t;
+
+
+
+/** Modem Control Signaling.
+ *  These are requests sent 'down-wards' in the stack.
+ *  Flow ON, OFF can be indicated to the modem.
+ *
+ */
+typedef enum _caif_modemcmd_t {
+	/** Flow Control is ON, transmit function can start sending data */
+	CAIF_MODEMCMD_FLOW_ON_REQ = 0,
+	/** Flow Control is OFF, transmit function should stop sending data */
+	CAIF_MODEMCMD_FLOW_OFF_REQ = 1,
+	/** Notify physical layer that it is in use */
+	_CAIF_MODEMCMD_PHYIF_USEFULL = 3,
+	/** Notify physical layer that it is no longer in use */
+	_CAIF_MODEMCMD_PHYIF_USELESS = 4
+} caif_modemcmd_t;
+
+/** CAIF Packet Direction.
+ *  Indicate if a packet is to be sent \b out or to be received \b in.
+ *
+ *
+ */
+typedef enum _caif_direction_t {
+	CAIF_DIR_IN = 0,	/*!< Incoming packet received. */
+	CAIF_DIR_OUT = 1	/*!< Outgoing packet to be transmitted. */
+} caif_direction_t;
+
+/*!
+ *  Receive Function.
+ *  Contract: Each layer must implement a receive function passing the Caif
+ *  Packets upwards in the stack.
+ *	Packet handling rules:
+ *	      -# The CAIF Packet (cfpkt) cannot be accessed after passing i
+ *		     to the next layer using up->receive().
+ *	      -# If parsing of the packet fail, the packet must be destroyed
+ *		     and -1 returned from the function.
+ *	      -# If parsing succeeds (and above layers return ok) function
+ *		     must return value > 0.
+ *
+ *  @param[in] layr Pointer to the current layer the receive function is
+ *		implemented for (this pointer).
+ *  @param[in] cfpkt Pointer to CaifPacket to be handled.
+ *  @return result < 0 indicates an error, 0 or positive value indicate success.
+ */
+typedef int (*receive_cb_t) (layer_t *layr, struct _cfpkt_t *cfpkt);
+
+/*!
+ *  Transmit Function.
+ *  Contract: Each layer must implement a transmit function passing the Caif
+ *	Packet downwards in the stack.
+ *	Packet handling rules:
+ *	      -# The CAIF Packet (cfpkt) ownership is passed to the transmit
+ *		 function. This means that the the packet cannot be access
+ *		 after passing it to the below layer using dn->transmit().
+ *
+ *
+ *	      -# However if transmit failes, the ownership is returned to
+ *		 caller. The caller of "dn->transmit()" must destroy or
+ *		 resend packet.
+ *
+ *	      -# Return less than zero means error, greater than zero means OK.
+ *
+ *  @param[in] layr  Pointer to the current layer the receive function is
+ *			     implemented for (this pointer).
+ *  @param[in] cfpkt Pointer to CaifPacket to be handled.
+ *  @param[in] info  Info about physical layer (filled in by MUX layer) and
+			     CAIF header size (each layer adds to hdr_len).
+ *  @return	     result < 0 indicates an error, 0 or positive value
+ *		     indicate success.
+ */
+typedef int (*transmit_cb_t) (layer_t *layr, transmt_info *info,
+		      struct _cfpkt_t *cfpkt);
+
+/*!
+ *  Control Function used to signal upwards in the CAIF stack.
+ *  Used for signaling responses (CAIF_CTRLCMD_*_RSP)
+ *  and asynchronous events from the modem  (CAIF_CTRLCMD_*_IND)
+ *
+ *  @param[in] layr  Pointer to the current layer the receive function is
+ *		     implemented for (this pointer).
+ *  @param[in] ctrl  Control Command.
+ */
+typedef void
+ (*ctrlcmd_cb_t) (layer_t *layr, caif_ctrlcmd_t ctrl, int phyid);
+
+/*!
+ *  Control Function used for controlling the modem. Used to signal down-wards
+ *  in the CAIF stack.
+ *  @returns 0 on success, < 0 upon failure.
+ *  @param[in] layr  Pointer to the current layer the receive function is
+ *		     implemented for (this pointer).
+ *  @param[in] ctrl  Control Command.
+ */
+typedef int (*modemcmd_cb_t) (layer_t *layr, caif_modemcmd_t ctrl);
+
+/*!
+ *  This function is used by the CAIF-Manager for initiating the adaptation
+ *  layer.
+ *  @param in caifstack The instance of layer below the adaptation layer in
+ *  the CAIF stack (service layer)
+ *  @param in pktfuncs The packet functions needed to create a packet is
+ *  passed in this structure
+ *  @param out adap_layer This layer is allocated and returned from the
+ *  adaptaion layer, and is inserted
+ *  in the CAIF stack as the topmost layer.
+ *
+ */
+typedef void
+ (*init_adaptation_layer) (layer_t *caifstack,
+			   caif_packet_funcs_t *pktfuncs,
+			   layer_t **adap_layer);
+
+
+/** This structure defines the generic layered structure in CAIF.
+ *  It is inspired by the "Protocol Layer Design Pattern" (Streams).
+ *
+ *  It defines a generic layering structure, used by all CAIF Layers and the
+ *  layers interfacing CAIF.
+ *
+ *  In order to integrate with CAIF an adaptation layer on top of the CAIF stack
+ *  and PHY layer below the CAIF stack
+ *  must be implemented. These layer must follow the design principles below.
+ *
+ *  Principles for layering of protocol layers:
+ *    -# All layers must use this structure. If embedding it, then place this
+ *	     structure first in the layer specific structure.
+ *    -# Each layer should not depend on any others layer private data.
+ *    -# In order to send data upwards do
+ *       \code layer->up->receive(layer->up, packet); \endcode
+ *       \see {receive_cb_t }
+ *    -# In order to send data downwards do
+ *       \code layer->dn->transmit(layer->dn, info, packet); \endcode
+ *       \see {transmit_cb_t }
+ *
+ *
+ *
+ */
+struct _layer_t {
+
+	struct _layer_t *up;	/*!< Pointer to the layer above */
+	struct _layer_t *dn;	/*!< Pointer to the layer below */
+	receive_cb_t receive;	/*!< Pointer to the receive function for this
+				 *   layer,used by the layer below to pass data
+				 *   upwards in the CAIF stack.*/
+	transmit_cb_t transmit;	/*!< Pointer to the transmit function used for
+				 *   the layer above to pass packet to be
+				 *   sent out on the stack.*/
+	ctrlcmd_cb_t ctrlcmd;	/*!< Pointer to function used by the CAIF stack
+				 *    to signal to the layer above.*/
+	modemcmd_cb_t modemcmd;	/*!< Pointer to function used by the CAIF stack
+				 * to signal to the layer below. */
+	struct _layer_t *next;	/*!< Pointer to chain of layers, up/dn will
+				 *   then point at the first element of a
+				 *   which then should be iterated through
+				 * the next pointer.*/
+	unsigned short prio;	/*!< Priority of this layer */
+	unsigned int id;	/*!< The identity of this layer. */
+	unsigned int type;	/*<! The type of this layer */
+	char name[9];		/*!< Name of the layer */
+};
+
+/** Set the up pointer for a specified layer.
+ *  @param layr Layer where up pointer shall be set.
+ *  @param above Layer above.
+ */
+#define layer_set_up(layr, above) ((layr)->up = (struct _layer_t *)(above))
+
+/** Set the dn pointer for a specified layer.
+ *  @param layr Layer where down pointer shall be set.
+ *  @param below Layer below.
+ */
+#define layer_set_dn(layr, below) ((layr)->dn = (struct _layer_t *)(below))
+
+/**
+ *  Transmit info, passed down-wards in protocol layers.
+ */
+struct _transmt_info {
+  /** Channel ID of the logical CAIF connection.
+   *  Is used by Service Layer to indicate to mux the PHY-layer
+   *  (Physical-ID) to send packet over.
+   */
+	unsigned short channel_id;
+
+  /** Physical ID of the logical physical connection.
+   *  Used by Service Layers to identify their physical id to Caif MUX (CFMUXL)
+   *  so that the MUX can add the
+   *  correct physical Id to the packet.
+   */
+
+	unsigned short phid;
+  /** Header Length, used to align pay load on 32bit boundary.
+   *  Used by SPI Layer (CFSPIL) to align start of pay-load data (IP header
+   *  start) to 16 or 32 bits boundary.
+   *  All layers add the number of header bytes they are using, then SPI
+   *  layer adds padding to get correct alignment.
+   */
+
+	unsigned short hdr_len;
+	/** Packet priority. */
+	unsigned char prio;
+};
+
+/** Packet functions needed by Adaptation layer and PHY layer are exported in
+ *  this structure
+ *
+ */
+struct _caif_packet_funcs_t {
+
+
+  /** Used map from a "native" packet e.g. Linux Socket Buffer to a CAIF packet.
+   *  @param dir - Direction telling if this is an packet to be sent or received
+   *  @param nativepkt	- The native packet to be transformed to a CAIF packe
+   *  @returns the mapped CAIF Packet CFPKT.
+   */
+	cfpkt_t *
+	    (*cfpkt_fromnative)(caif_direction_t dir, void *nativepkt);
+
+  /** Used map from a CAIF packet to a "native" packet e.g. Linux Socket Buffer.
+   *  @param pkt  - The CAIF packet to be transformed to a "native" packet.
+   *  @returns The native packet transformed from a CAIF packet.
+   */
+	void *(*cfpkt_tonative)(cfpkt_t *pkt);
+
+  /** Used by "app" layer to create an outgoing CAIF packet to be sent ou
+   *  of the CAIF Stack.
+   *  @param data - Packet data to copy into the packet. If NULL copying will
+   *		     not take place.
+   *  @param len  - Length of data to copy into the packe
+   *  @returns a new CAIF Packet CFPKT.
+   *  @deprecated Use \b cfpkt_create_pkt (above) instead.
+   */
+	cfpkt_t *
+	    (*cfpkt_create_recv_pkt)(const unsigned char *data,
+				      unsigned int len);
+
+  /** Used by PHY layer to create an incoming CAIF packet to be processed by
+   *  the CAIF Stack.
+   *  @param data - Packet data to copy into the packet. If NULL copying
+   *  will not take place.
+   *  @param len  - Length of data to copy into the packe
+   *  @returns a new CAIF Packet CFPKT.
+   *  @deprecated Use \b cfpkt_create_pkt (above) instead.
+   */
+	cfpkt_t *
+	    (*cfpkt_create_xmit_pkt)(const unsigned char *data,
+				      unsigned int len);
+
+  /** Used to extract data from a CAIF packe
+   *  @param cfpkt	 Packet to extract data from.
+   *  @param buf	 Buffer to hold the data to be extracted from the
+   *			 CAIF packet.
+   *  @param buflen	 Length of the buffer (maximum length of the data to
+   *			 copy into the buffer).
+   *  @param actual_len	 Amount of bytes copied from the packet into the buffer.
+   */
+	void
+	 (*cfpkt_extract)(cfpkt_t *cfpkt, void *buf, unsigned int buflen,
+			   unsigned int *actual_len);
+
+  /** Releases a CAIF Packe
+   *  @param cfpkt	 Packet to destroy.
+   */
+	void
+	 (*cfpkt_destroy)(cfpkt_t *cfpkt);
+
+
+
+/** Append by giving user access to packet buffer
+ * @param pkt Packet to append to
+ * @param buf Buffer inside pkt that user shall copy data into
+ * @param buflen Length of buffer and number of bytes added to packe
+ * @return < 0 on error
+ */
+
+	 int (*cfpkt_raw_append)(cfpkt_t *cfpkt, void **buf,
+				unsigned int buflen);
+
+/** Extract by giving user access to packet buffer
+ * @param pkt Packet to extract from
+ * @param buf Buffer inside pkt that user shall copy data from
+ * @param buflen Length of buffer and number of bytes removed from packe
+ * @return < 0 on error
+ */
+	 int (*cfpkt_raw_extract)(cfpkt_t *cfpkt, void **buf,
+				 unsigned int buflen);
+
+
+  /** Creates a packet queue */
+	cfpktq_t *(*cfpktq_create)(void);
+
+  /** Inserts a packet into the packet queue, packets are ordered by priority.
+   *  If the same priority is used packets are ordered as a FIFO.
+   */
+	void (*cfpkt_queue)(cfpktq_t *pktq, cfpkt_t *pkt,
+			     unsigned short prio);
+
+
+  /** Peek into the first packet in the queue */
+	cfpkt_t *(*cfpkt_qpeek)(cfpktq_t *pktq);
+
+  /** Dequeue a packet from the queue */
+	cfpkt_t *(*cfpkt_dequeue)(cfpktq_t *pktq);
+
+  /** Get length of a packet */
+	uint16(*cfpkt_getlen)(cfpkt_t *pkt);
+
+};
+
+/*! @} */
+
+#endif				/* CAIF_LAYER_H_ */
diff --git a/include/net/caif/generic/cfcnfg.h b/include/net/caif/generic/cfcnfg.h
new file mode 100644
index 0000000..9c3aeb3
--- /dev/null
+++ b/include/net/caif/generic/cfcnfg.h
@@ -0,0 +1,223 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+
+#ifndef CFCNFG_H_
+#define CFCNFG_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfctrl.h>
+struct _cfctrl_t;
+struct _cfcnfg_t;
+
+/** CAIF Configuration Layer (CFCNFG)*/
+typedef struct _cfcnfg_t cfcnfg_t;
+
+/*! \addtogroup GenCaifExternal
+ *  Additional documentation for group `GenCaifExternal'
+ *  @{
+ */
+
+
+/** Types of Physical Layers defined in CAIF Stack */
+typedef enum _cfcnfg_phy_type_t {
+	CFPHYTYPE_UNKNOWN = 0,
+	CFPHYTYPE_SERIAL = 1,	/*!< Serial Physical Interface */
+	CFPHYTYPE_SPI = 2,	/*!< SPI Physical Interface */
+	CFPHYTYPE_MSL = 3,	/*!< MSL Physical Interface */
+	CFPHYTYPE_SHM = 4,	/*!< Shared Memory Physical Interface */
+	CFPHYTYPE_LOOP = 5,	/*!< Loopback Physical Interface */
+	_CFPHYTYPE_MAX = 6
+} cfcnfg_phy_type_t;
+
+/** Physical Preference - HW Abstraction */
+typedef enum _cfcnfg_phy_preference_t {
+	/** Default Physical Interface */
+	CFPHYPREF_UNSPECIFIED = 0xa0,
+	/** Default Physical Interface for Low Latency Traffic */
+	CFPHYPREF_LOW_LAT = 0xd0,
+	/** Default Physical Interface for High Bandwidth Traffic */
+	CFPHYPREF_HIGH_BW = 0xe0,
+	/** \b TEST \b ONLY Loop-back Interface Simulating Acc side responses */
+	CFPHYPREF_LOOP = 0x70,
+	/** \b TEST \b ONLY Raw loopback interface */
+	CFPHYPREF_RAW_LOOP = 0x80
+} cfcnfg_phy_preference_t;
+
+/** Types of CAIF Links defined in CAIF Stack
+ * @obsolete
+ */
+typedef enum _cfcnfg_link_type_t {
+	_CF_DECM = 0,		/*!< DECM link - NOT SUPPORTED */
+	CF_VEI = CFCTRL_SRV_VEI,	/*!< VEI link - AT */
+	CF_VIDEO = CFCTRL_SRV_VIDEO,	/*!< Video Link */
+	CF_DEBUG = CFCTRL_SRV_DBG,	/*!< Debug Link */
+	CF_DATAGRAM = CFCTRL_SRV_DATAGRAM,	/*!< Datagram link */
+	CF_RFM = CFCTRL_SRV_RFM,	/*!< RFM link */
+	CF_UTILITY = CFCTRL_SRV_UTIL	/*!< Utility link */
+} cfcnfg_link_type_t;
+
+
+/** Configuration parameters for a physical layer (e.g. Serial) */
+typedef struct cfcnfg_phy_param_t {
+	int foo;
+} cfcnfg_phy_param_t;
+
+/** Configuration information used to setup the CAIF Physical Interface */
+typedef struct cfcnfg_phy_config {
+	/** CAIF Physical Type */
+	cfcnfg_phy_type_t phy_type;
+	/** Instance Number, e.g. Uart Number */
+	uint8 phy_sub_instance;
+	/** Preference LowLatency/HighBandwithd */
+	cfcnfg_phy_preference_t pref;
+	/** Device Name */
+	char name[20];
+	/** Cheksum is used for Interface */
+	bool checksum;
+	/** Configuration param specific for the PHY Type */
+	cfcnfg_phy_param_t param;
+	/** Pointer to layer above */
+	layer_t *up;
+} cfcnfg_phy_config_t;
+
+/** Registration information used to setup the CAIF Physical Interface */
+typedef struct cfcnfg_phy_mgmt {
+	/** Registation of type */
+	cfcnfg_phy_type_t type;
+	/** Creates an instance of the physical layer (e.g. Serial)
+	 * and configures it */
+	layer_t *(*create_phy) (cfcnfg_phy_config_t *config);
+	 /** Delete an instance of the physical layer (e.g. Serial) */
+	int (*delete_phy) (layer_t *l);
+} cfcnfg_phy_mgmt_t;
+
+
+
+
+/**
+ * This variable is used as a global flag in order to set if STX is used on
+ * serial communication.
+ *  NOTE: This is not a fully future proof solution.
+ */
+
+extern int serial_use_stx;
+
+
+/**
+ * Create the CAIF Configuration Object.
+ * \image html CreateCaifConfig.jpg "Create Caif Configuration Object."
+ * @returns the created instance of a CFCNFG object.
+ */
+cfcnfg_t *cfcnfg_create(void);
+
+/**
+ * Adds a physical layer to the CAIF stack.
+ * \image html AddPhyCaifConfig.jpg "Add a PHY layer to CAIF Stack."
+ * @param cnfg Pointer to the Caif Configuration Class, created by
+ *				fcnfg_create().
+ * @param phy_type Specifies the type of physical interface e.g.
+ *		    CFPHYTYPE_SERIAL.
+ * @param phy_layer Specify the physical layer, the transmit function
+ *		    MUST be set in the structure.
+ * @param phyid [out] The assigned physical ID for this layer,
+ *		      used in \ref cfcnfg_add_adapt_layer to specify
+ *		      PHY for the link.
+ */
+
+void
+cfcnfg_add_phy_layer(cfcnfg_t *cnfg, cfcnfg_phy_type_t phy_type,
+		     layer_t *phy_layer, uint16 *phyid,
+		     cfcnfg_phy_preference_t pref);
+
+/**
+ * Deletes a Adaptation Layer from the CAIF Stack.
+ *
+ * @param cnfg Pointer to the CAIF Configuration Class, created by
+ *			   cfcnfg_create().
+ * @param adap_layer Adaptation layer to be removed.
+ * @return true on success, false upon failure.
+ */
+
+bool cfcnfg_del_adapt_layer(struct _cfcnfg_t *cnfg, layer_t *adap_layer);
+
+/**
+ * Adds a Adaptation Layer to the CAIF Stack.
+ * The Adaptation Layer is where the interface to application or higher-level
+ * driver functionality is implemented.
+ * \image html AddVeiCaifConfig.jpg "Add an Adaptation layer to CAIF Stack."
+ *
+ * @param cnfg	     Pointer to the CAIF Configuration Class, created by
+ *		     cfcnfg_create().
+ * @param linktype   Type of link which is set up e.g. CF_AT_PLAIN.
+ * @param connid     Connection ID, used for data-gram links.
+ * @param phyid	     PHY ID received from \ref	cfcnfg_add_phy_layer,
+ *		     specifying the PHY device to use for this link.
+ * @param adap_layer Specify the adaptation layer, the receive
+ *		     and flow-control functions MUST be set in the structure.
+ * @return	     true on success, false upon failure.
+ */
+bool
+cfcnfg_add_adapt_layer(cfcnfg_t *cnfg, cfcnfg_link_type_t linktype,
+		       uint32 connid, uint16 phyid, layer_t *adap_layer);
+
+
+
+/**
+ * Adds a Adaptation Layer to the CAIF Stack.
+ * The Adaptation Layer is where the interface to application or higher-level
+ * driver functionality is implemented.
+ * \image html AddVeiCaifConfig.jpg "Add an Adaptation layer to CAIF Stack."
+ *
+ * @param cnfg			Pointer to the CAIF Configuration Class, created by
+ *						cfcnfg_create().
+ * @param param			Link setup parameters.
+ * @param adap_layer	Specify the adaptation layer, the receive and flow-control functions MUST be set in the structure.
+ * @return				true on success, false upon failure.
+ */
+bool
+cfcnfg_add_adaptation_layer(cfcnfg_t *cnfg, cfctrl_link_param_t *param,
+			    layer_t *adap_layer);
+
+
+/**
+ * Returns a handle to the Packet Functions used to create packets with
+ * content, and extract information from packets.
+ */
+caif_packet_funcs_t cfcnfg_get_packet_funcs(void);
+
+/** Get Physical Id given type.
+ * @return Returns one of the physical interfaces matching the given type.
+ *	   Zero if no match is found.
+ */
+int cfcnfg_get_phyid(cfcnfg_t *cnfg, cfcnfg_phy_preference_t phy_pref);
+
+
+/** Get Physical Id given name.
+ * @return Returns the physical interface matching the specified name.
+ */
+int cfcnfg_get_named(cfcnfg_t *cnfg, char *name);
+
+int cfcnfg_instanciate(cfcnfg_t *cnfg, cfcnfg_phy_config_t *phy_config);
+int cfcnfg_instanciate2(cfcnfg_t *cnfg, cfcnfg_phy_type_t phy_type,
+			uint8 instance, char *name, bool checksum,
+			cfcnfg_phy_preference_t pref,
+			cfcnfg_phy_param_t *param);
+int cfcnfg_delete_phy_inst(cfcnfg_t *cfg, char *name);
+int cfcnfg_unregister_phy_type(cfcnfg_t *cfg, cfcnfg_phy_type_t type);
+int cfcnfg_register_phy_type(cfcnfg_t *cfg, cfcnfg_phy_mgmt_t *mgmt);
+int cfcnfg_del_phy_layer(struct _cfcnfg_t *cnfg, layer_t *phy_layer);
+
+/*! @} */
+#endif				/* CFCNFG_H_ */
diff --git a/include/net/caif/generic/cfctrl.h b/include/net/caif/generic/cfctrl.h
new file mode 100644
index 0000000..e9444ea
--- /dev/null
+++ b/include/net/caif/generic/cfctrl.h
@@ -0,0 +1,139 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFCTRL_H_
+#define CFCTRL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfsrvl.h>
+
+
+/* CAIF Control packet commands*/
+typedef enum {
+	CFCTRL_CMD_LINK_SETUP = 0,
+	CFCTRL_CMD_LINK_DESTROY = 1,
+	CFCTRL_CMD_LINK_ERR = 2,
+	CFCTRL_CMD_ENUM = 3,
+	CFCTRL_CMD_SLEEP = 4,
+	CFCTRL_CMD_WAKE = 5,
+	CFCTRL_CMD_LINK_RECONF = 6,
+	CFCTRL_CMD_START_REASON = 7,
+	CFCTRL_CMD_RADIO_SET = 8,
+	CFCTRL_CMD_MODEM_SET = 9,
+	CFCTRL_CMD_DATA = 0,
+	CFCTRL_CMD_MASK = 0xf
+} cfctrl_cmd_t;
+
+typedef enum {
+	CFCTRL_SRV_DECM = 0,
+	CFCTRL_SRV_VEI = 1,
+	CFCTRL_SRV_VIDEO = 2,
+	CFCTRL_SRV_DBG = 3,
+	CFCTRL_SRV_DATAGRAM = 4,
+	CFCTRL_SRV_RFM = 5,
+	CFCTRL_SRV_UTIL = 6,
+	CFCTRL_SRV_MASK = 0xf
+} cfctrl_srv_t;
+
+#define CFCTRL_RSP_BIT 0x20
+#define CFCTRL_ERR_BIT 0x10
+typedef void
+ (*cfctrl_rspcp_t) (void);
+
+
+
+typedef void
+ (*cfctrl_linkdestroy_rspcb_t) (layer_t *layer, uint8 linkid,
+				layer_t *client_layer);
+
+typedef void
+ (*cfctrl_linksetup_rspcb_t) (layer_t *layer, uint8 linkid,
+			      cfctrl_srv_t serv, uint8 phyid,
+			      layer_t *adapt_layer);
+
+typedef struct _cfctrl_rsp_t {
+	cfctrl_linksetup_rspcb_t linksetup_rsp;
+	cfctrl_linkdestroy_rspcb_t linkdestroy_rsp;
+	cfctrl_rspcp_t linkerror_ind;
+	cfctrl_rspcp_t enum_rsp;
+	cfctrl_rspcp_t sleep_rsp;
+	cfctrl_rspcp_t wake_rsp;
+	cfctrl_rspcp_t restart_rsp;
+	cfctrl_rspcp_t radioset_rsp;
+	cfctrl_linkdestroy_rspcb_t reject_rsp;
+} cfctrl_rsp_t;
+
+/** Link Setup Parameters for CAIF-Links. */
+typedef struct _cfctrl_link_param_t {
+	cfctrl_srv_t linktype;/*!< (T3,T0) Type of Channel */
+	uint8 priority;		  /*!< (P4,P0) Priority of the channel */
+	uint8 phyid;		  /*!< (U2-U0) Physical interface to connect */
+	uint8 endpoint;		  /*!< (E1,E0) Endpoint for data channels */
+	uint8 chtype;		  /*!< (H1,H0) Channel-Type,
+					       applies to VEI, DEBUG */
+	union {
+		struct {
+			uint8 connid;	/*!<  (D7,D0) Video LinkId */
+		} video;
+
+		struct {
+			uint32 connid;	/*!< (N31,Ngit0) Connection ID used
+					 *		  for Datagram */
+		} datagram;
+
+		struct {
+			uint32 connid;	/*!< Connection ID used for RFM */
+			char volume[20];	/*!< Volume to mount for RFM */
+		} rfm;		/*!< Configuration for RFM */
+
+		struct {
+			uint16 fifosize_kb;	/*!< Psock FIFO size in KB */
+			uint16 fifosize_bufs;	/*!< Psock # signal buffers */
+			char name[16];	/*!< Name of the PSOCK service */
+			uint8 params[255];	/*!< Link setup Parameters> */
+			uint16 paramlen;	/*!< Length of Link Setup
+						 *    Parameters */
+		} utility;	/*!< Configuration for Utility Links (Psock) */
+	} u;
+} cfctrl_link_param_t;
+
+/** This structure is used internally in CFCTRL */
+struct cfctrl_request_info {
+	int sequence_no;
+	cfctrl_cmd_t cmd;
+	uint8 channel_id;
+	cfctrl_link_param_t param;
+	struct cfctrl_request_info *next;
+	layer_t *client_layer;
+};
+
+
+void cfctrl_enum_req(layer_t *cfctrl, uint8 physlinkid);
+
+
+
+void cfctrl_linkup_request(layer_t *cfctrl, cfctrl_link_param_t *param,
+			   layer_t *user_layer);
+
+
+void cfctrl_linkdown_req(layer_t *cfctrl, uint8 linkid, layer_t *client);
+void cfctrl_sleep_req(layer_t *cfctrl);
+void cfctrl_wake_req(layer_t *cfctrl);
+void cfctrl_getstartreason_req(layer_t *cfctrl);
+
+layer_t *cfctrl_create(void);
+void cfctrl_set_dnlayer(layer_t *this, layer_t *dn);
+void cfctrl_set_uplayer(layer_t *this, layer_t *up);
+void cfctrl_set_respfuncs(layer_t *this, cfctrl_rsp_t *respfuncs);
+#endif				/* CFCTRL_H_ */
diff --git a/include/net/caif/generic/cffrml.h b/include/net/caif/generic/cffrml.h
new file mode 100644
index 0000000..35e2e8a
--- /dev/null
+++ b/include/net/caif/generic/cffrml.h
@@ -0,0 +1,29 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFFRM_H_
+#define CFFRM_H_
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cflst.h>
+
+struct _cffrml_t;
+typedef struct _cffrml_t cffrml_t;
+layer_t *cffrml_create(uint16 phyid, bool DoFCS);
+void cffrml_set_uplayer(layer_t *this, layer_t *up);
+void cffrml_set_dnlayer(layer_t *this, layer_t *dn);
+void cffrml_destroy(layer_t *layer);
+
+#endif				/* CFFRM_H_ */
diff --git a/include/net/caif/generic/cfglue.h b/include/net/caif/generic/cfglue.h
new file mode 100644
index 0000000..0930309
--- /dev/null
+++ b/include/net/caif/generic/cfglue.h
@@ -0,0 +1,206 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+/*
+ *    Description: This file contains the OS and HW dependencies for CAIF.
+ */
+
+
+#ifndef CFGLU_H_
+#define CFGLU_H_
+
+/*! \addtogroup GenCaifGlue
+ *  Additional documentation for group `GenCaifGlue'
+ *  @{
+ */
+
+
+#define CFLOG_LEVEL_ERROR   1
+#define CFLOG_LEVEL_WARNING 2
+#define CFLOG_LEVEL_TRACE   3
+#define CFLOG_LEVEL_TRACE2  4
+#define CFLOG_LEVEL_TRACE3  5
+#define CFLOG_LEVEL_FUNC    6
+
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include "linux/stddef.h"
+#include "linux/types.h"
+
+
+/** Unsigned 8 bit */
+typedef __u8 uint8;
+
+/** Unsigned 16 bit */
+typedef __u16 uint16;
+
+/** Unsigned 32 bit */
+typedef __u32 uint32;
+
+
+/******************************************
+ *  HANDLING ENDIANNES.
+ *  CAIF uses little-endian byte order.
+ ******************************************/
+
+/** CAIF Endian handling Net to Host of 16 bits unsigned */
+#define cfglu_le16_to_cpu(v)  le16_to_cpu(v)
+
+/** CAIF Endian handling Host to Net of 16 bits unsigned */
+#define cfglu_cpu_to_le16(v)  cpu_to_le16(v)
+
+/** CAIF Endian handling Host to Net of 32 bits unsigned */
+#define cfglu_le32_to_cpu(v)  le32_to_cpu(v)
+
+/** CAIF Endian handling Net to Host of 32 bits unsigned */
+#define cfglu_cpu_to_le32(v)  cpu_to_le32(v)
+
+extern int caif_dbg_level;
+
+
+/* LOGGING */
+
+#define _CFLOG_FATAL(format, args...) \
+	do {if (caif_dbg_level > CFLOG_LEVEL_ERROR) {\
+		printk(KERN_ERR "<%s:%d, FATAL> " format "\n",\
+				__func__, __LINE__ ,  ## args); } } while (0)
+
+#define CFLOG_FATAL(format) _CFLOG_FATAL format
+
+/** CAIF Error Logging. */
+#define _CFLOG_ERROR(format, args...)\
+	do {if (caif_dbg_level > CFLOG_LEVEL_ERROR) {\
+		printk(KERN_ERR "<%s:%d, ERROR> " format "\n",\
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_ERROR(format)  _CFLOG_ERROR format
+
+/** CAIF Warning Logging. */
+#define _CFLOG_WARN(format, args...)\
+	do {if (caif_dbg_level > CFLOG_LEVEL_WARNING) {\
+		printk(KERN_WARNING "<%s:%d, WARN> "  format "\n",\
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#ifdef CAIF_DEBUG_ON
+#define CFLOG_WARN(format)   _CFLOG_WARN format
+
+/** CAIF Trace Control Logging. Level 1 control trace (Channel setup etc) */
+#define _CFLOG_TRACE(format, args...)  \
+	do { if (caif_dbg_level > CFLOG_LEVEL_TRACE) {\
+		printk(KERN_INFO "<%s:%d, TRACE> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_TRACE(format)  _CFLOG_TRACE format
+
+/** CAIF Trace Payload Logging. Level payload trace */
+#define _CFLOG_TRACE2(format, args...) \
+	do {if (caif_dbg_level > CFLOG_LEVEL_TRACE2) {\
+		printk(KERN_INFO "<%s:%d, TRACE2> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_TRACE2(format) _CFLOG_TRACE2 format
+
+/** CAIF Trace Detailed Logging including packet dumps */
+#define _CFLOG_TRACE3(format, args...)\
+	do {if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {\
+		printk(KERN_INFO "<%s:%d, TRACE3> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+
+#define CFLOG_TRACE3(format) _CFLOG_TRACE3 format
+
+/** CAIF Trace Entering Function */
+#define _CFLOG_ENTER(format, args...) \
+	do {if (caif_dbg_level > CFLOG_LEVEL_FUNC) {\
+		printk("KERN_INFO <%s:%d, ENTER> " format, \
+				__func__, __LINE__ ,  ## args); } }  while (0)
+#define CFLOG_ENTER(format)  _CFLOG_ENTER format
+
+/** CAIF Trace Exiting Function */
+
+#define _CFLOG_EXIT(format, args...)  \
+	do {if (caif_dbg_level > CFLOG_LEVEL_FUNC) {\
+		printk("KERN_INFO <%s:%d, EXIT> "  format "\n",\
+				__func__, __LINE__ ,  ## args); } }  while (0)
+#define CFLOG_EXIT(format)   _CFLOG_EXIT format
+
+#else
+
+#define CFLOG_WARN(args)
+#define CFLOG_TRACE(args)
+#define CFLOG_TRACE2(args)
+#define CFLOG_TRACE3(args)
+#define CFLOG_ENTER(args)
+#define CFLOG_EXIT(args)
+
+#endif
+
+
+
+
+
+/* Critical Section support, one thread only between startsync
+ * and endsync */
+#define cfglu_lock_t spinlock_t
+#define cfglu_init_lock(sync) spin_lock_init(&(sync))
+#define cfglu_lock(sync) spin_lock(&(sync))
+#define cfglu_unlock(sync) spin_unlock(&(sync))
+#define cfglu_deinit_lock(sync)
+
+/* Read/Write lock, allows multiple readers, one writer */
+#define cfglu_rwlock_t rwlock_t
+#define cfglu_init_rwlock(rwlock) rwlock_init(&(rwlock))
+#define cfglu_deinit_rwlock(rwlock)
+#define cfglu_read_lock(rwlock)   read_lock(&rwlock)
+#define cfglu_read_unlock(rwlock) read_unlock(&rwlock)
+#define cfglu_write_lock(rwlock)    write_lock(&rwlock)
+#define cfglu_write_unlock(rwlock)  write_unlock(&rwlock)
+
+
+
+/* Atomic counting */
+#define cfglu_atomic_t atomic_t
+#define cfglu_atomic_read(a) atomic_read(&a)
+#define cfglu_atomic_set(a, val) atomic_set(&a, val)
+#define cfglu_atomic_inc(a) atomic_inc(&a)
+#define cfglu_atomic_dec(a) atomic_dec(&a)
+
+/* HEAP */
+#define cfglu_alloc(size) kmalloc(size, GFP_KERNEL)
+#define cfglu_free(ptr) kfree(ptr)
+
+/* ASSERT */
+#define cfglu_assert(exp) BUG_ON(!(exp))
+
+
+#define cfglu_container_of(p, t, m) container_of(p, t, m)
+
+/*FIXME: Comment error codes*/
+enum cfglu_errno {
+	CFGLU_EOK = 0,
+	CFGLU_EPKT = -EPROTO,
+	CFGLU_EADDRINUSE = -EADDRINUSE,
+	CFGLU_EIO = -EIO,
+	CFGLU_EFCS = -EILSEQ,
+	CFGLU_EBADPARAM = -EINVAL,
+	CFGLU_EINVAL = -EINVAL,
+	CFGLU_ENODEV = -ENODEV,
+	CFGLU_ENOTCONN = -ENOTCONN,
+	CFGLU_EPROTO = -EPROTO,
+	CFGLU_EOVERFLOW = -EOVERFLOW,
+	CFGLU_ENOMEM = -ENOMEM,
+	CFGLU_ERETRY = -EAGAIN,
+	CFGLU_ENOSPC = -ENOSPC,
+	CFGLU_ENXIO = -ENXIO
+
+};
+
+#endif				/* CFGLU_H_ */
diff --git a/include/net/caif/generic/cfloopcfg.h b/include/net/caif/generic/cfloopcfg.h
new file mode 100644
index 0000000..a041f49
--- /dev/null
+++ b/include/net/caif/generic/cfloopcfg.h
@@ -0,0 +1,28 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFLOOPCFG_H_
+#define CFLOOPCFG_H_
+#include <net/caif/generic/caif_layer.h>
+struct _cfloopcfg_t {
+	layer_t *loop;
+};
+typedef struct _cfloopcfg_t cfloopcfg_t;
+cfloopcfg_t *cfloopcfg_create(void);
+void cfloopcfg_add_phy_layer(cfloopcfg_t *cnfg,
+			     cfcnfg_phy_type_t phy_type,
+			     layer_t *phy_layer);
+
+#endif				/* CFLOOPCFG_H_ */
diff --git a/include/net/caif/generic/cflst.h b/include/net/caif/generic/cflst.h
new file mode 100644
index 0000000..073fa22
--- /dev/null
+++ b/include/net/caif/generic/cflst.h
@@ -0,0 +1,27 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFLST_H_
+#define CFLST_H_
+
+#include <net/caif/generic/cfglue.h>
+bool cflst_put(layer_t **lst, uint8 id, layer_t *node);
+layer_t *cflst_get(layer_t **lst, uint8 id);
+layer_t *cflst_del(layer_t **lst, uint8 id);
+#define CFLST_FIRST(lst) lst
+#define CFLST_MORE(node) ((node) != NULL)
+#define CFLST_NEXT(node) ((node)->next)
+void cflst_init(layer_t **lst);
+#endif				/* CFLST_H_ */
diff --git a/include/net/caif/generic/cfmsll.h b/include/net/caif/generic/cfmsll.h
new file mode 100644
index 0000000..ad207c2
--- /dev/null
+++ b/include/net/caif/generic/cfmsll.h
@@ -0,0 +1,22 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFMSLL_H_
+#define CFMSLL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+layer_t *cfmsll_create(int type, int instance);
+
+#endif				/* CFMSLL_H_ */
diff --git a/include/net/caif/generic/cfmuxl.h b/include/net/caif/generic/cfmuxl.h
new file mode 100644
index 0000000..06747d3
--- /dev/null
+++ b/include/net/caif/generic/cfmuxl.h
@@ -0,0 +1,30 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFMUXL_H_
+#define CFMUXL_H_
+#include <net/caif/generic/caif_layer.h>
+struct _cfsrvl_t;
+struct _cffrml_t;
+
+layer_t *cfmuxl_create(void);
+bool cfmuxl_set_uplayer(layer_t *layr, layer_t *up, uint8 linkid);
+layer_t *cfmuxl_remove_dnlayer(layer_t *layr, uint8 phyid);
+bool cfmuxl_set_dnlayer(layer_t *layr, layer_t *up, uint8 phyid);
+layer_t *cfmuxl_remove_uplayer(layer_t *layr, uint8 linkid);
+bool cfmuxl_is_phy_inuse(layer_t *layr, uint8 phyid);
+uint8 cfmuxl_get_phyid(layer_t *layr, uint8 channel_id);
+
+#endif				/* CFMUXL_H_ */
diff --git a/include/net/caif/generic/cfpkt.h b/include/net/caif/generic/cfpkt.h
new file mode 100644
index 0000000..d8079c8
--- /dev/null
+++ b/include/net/caif/generic/cfpkt.h
@@ -0,0 +1,246 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFPKT_H_
+#define CFPKT_H_
+#include <net/caif/generic/caif_layer.h>
+
+
+struct _cfpkt_t;
+/*! \addtogroup GenCaifGlue
+ *  Additional documentation for group `GenCaifGlue'
+ *  @{
+ */
+
+/** Checksum iteration function used to iterate buffers
+ * (we may have packets consisting of a chain of buffers)
+ * @param chs Checksum calculated so far.
+ * @param buf pointer to the buffer to checksum
+ * @param len length of buf.
+ * @return checksum of buffer
+ */
+typedef uint16(*iterfunc_t)(uint16 chks, void *buf, uint16 len);
+
+caif_packet_funcs_t caif_get_packet_funcs(void);
+/** Create a Caif packet.
+ * @param len Length of packet to be created
+ * @returns new packet.
+ */
+cfpkt_t *cfpkt_create(uint16 len);
+/**
+ * Destroy a CAIF Packet.
+ * @param pkt Packet to be destoyed.
+ */
+void cfpkt_destroy(cfpkt_t *pkt);
+
+/**
+ * Extract header from packet.
+ *  \image html ExtractCaifPacketHeader.jpg "Extract Caif Packet Header"
+ *
+ * @param pkt Packet to extract header data from.
+ * @param data pointer to copy the header data into.
+ * @param len length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_extr_head(cfpkt_t *pkt, void *data, uint16 len);
+
+/**
+ * Peek header from packet.
+ * Reads data from packet without changing packet.
+ *
+ * @param pkt Packet to extract header data from.
+ * @param data pointer to copy the header data into.
+ * @param len length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_peek_head(cfpkt_t *pkt, void *data, uint16 len);
+
+/**
+ * Extract header from trailer (end of packet).
+ *  \image html ExtractCaifPacketTrailer.jpg "Extract Caif Packet Trailer"
+ *
+ * @param pkt Packet to extract header data from.
+ * @param data pointer to copy the trailer data into.
+ * @param len length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_extr_trail(cfpkt_t *pkt, void *data, uint16 len);
+/**
+ * Add header to packet.
+ *
+ *
+ * @param pkt Packet to add header data to.
+ * @param data pointer to copy into the header.
+ * @param len length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_add_head(cfpkt_t *pkt, const void *data, uint16 len);
+
+/**
+ * Add trailer to packet.
+ *
+ *
+ * @param pkt Packet to add trailer data from.
+ * @param data pointer to copy into the trailer.
+ * @param len length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_add_trail(cfpkt_t *pkt, const void *data, uint16 len);
+
+/**
+ * Pad trailer on packet.
+ * Moves data pointer in packet, no content copied.
+ *
+ * @param pkt Packet to add trailer data from.
+ * @param data pointer to copy into the trailer.
+ * @param len length of head data to copy.
+ * @return \ref true on success \ref false on failure
+ */
+bool cfpkt_pad_trail(cfpkt_t *pkt, uint16 len);
+
+/**
+ * Add a single byte to packet body (tail).
+ */
+
+bool cfpkt_addbdy(cfpkt_t *pkt, const uint8 data);
+
+/**
+ * Add a data to packet body (tail).
+ */
+bool cfpkt_add_body(cfpkt_t *pkt, const void *data, uint16 len);
+
+/**
+ * Checks if there is more data to process in packet.
+ * @param pkt Packet to check.
+ * @return \ref true on if more data is available in packet \ref false if no more data can be extracted
+ */
+bool cfpkt_more(cfpkt_t *pkt);
+/**
+ * Checks if the packet is erroneous, i.e. if it has been attempted to extract more data than available in packet
+ * or writing more data than has been allocated in \ref cfpkt_create().
+ * @param pkt Packet to check.
+ * @return \ref true on error \ref false otherwise
+ */
+bool cfpkt_erroneous(cfpkt_t *pkt);
+
+/**
+ * Get the packet length.
+ * @param pkt Packet to get lenght from.
+ * @return number of bytes in packet.
+ */
+uint16 cfpkt_getlen(cfpkt_t *pkt);
+
+/**
+ * Set the packet length, by adjusting the tailer pointer according to length.
+ * @param pkt Packet to set lenght.
+ * @param len Packet length.
+ * @return number of bytes in packet.
+ */
+int cfpkt_setlen(cfpkt_t *pkt, uint16 len);
+
+/**
+ * Appends a packet's data to another packet.
+ * NB: Input packets will be destroyed after appending and cannot be used
+ * after calling this function.
+ * @param dstpkt Packet to append data into, WILL BE FREED BY THIS FUNCTION
+ * @param addpkt Packet to be appended and automatically released, WILL BE FREED BY THIS FUNCTION.
+ * @param expectlen Packet's expected total length, this should be considered a hint.
+ * @returns the new appended packet.
+ */
+cfpkt_t *cfpkt_append(cfpkt_t *dstpkt, cfpkt_t *addpkt,
+		      uint16 expectlen);
+/**
+ * Split a packet into two packet at the specified split point.
+ * @param pkt Packet to be split
+ * @param pos Position to split packet in two part.
+ */
+cfpkt_t *cfpkt_split(cfpkt_t *pkt, uint16 pos);
+
+/** Iteration function, iterates the packet buffers from start to end*/
+uint16 cfpkt_iterate(cfpkt_t *pkt, iterfunc_t func, uint16 data);
+
+void
+cfpkt_extract(cfpkt_t *cfpkt, void *buf, unsigned int buflen,
+	      unsigned int *actual_len);
+
+/** Append by giving user access to packet buffer
+ * @param pkt Packet to append to
+ * @param buf Buffer inside pkt that user shall copy data into
+ * @param buflen Length of buffer and number of bytes added to packet
+ * @return 0 on error, 1 on success
+ */
+
+int cfpkt_raw_append(cfpkt_t *cfpkt, void **buf, unsigned int buflen);
+
+/** Extract by giving user access to packet buffer
+ * @param pkt Packet to extract from
+ * @param buf Buffer inside pkt that user shall copy data from
+ * @param buflen Length of buffer and number of bytes removed from packet
+ * @return 0 on error, 1 on success
+ */
+int cfpkt_raw_extract(cfpkt_t *cfpkt, void **buf, unsigned int buflen);
+
+
+
+/** Used map from a "native" packet e.g. Linux Socket Buffer to a CAIF packet.
+ *  @param dir - Direction telling if this is an packet to be sent or received.
+ *  @param nativepkt  - The native packet to be transformed to a CAIF packet
+ *  @returns the mapped CAIF Packet CFPKT.
+ */
+cfpkt_t *cfpkt_fromnative(caif_direction_t dir, void *nativepkt);
+
+/** Used map from a CAIF packet to a "native" packet e.g. Linux Socket Buffer.
+ *  @param pkt  - The CAIF packet to be transformed to a "native" packet.
+ *  @returns The native packet transformed from a CAIF packet.
+ */
+void *cfpkt_tonative(cfpkt_t *pkt);
+
+
+caif_packet_funcs_t cfpkt_get_packet_funcs(void);
+
+/**
+ * Insert a packet in the packet queue.
+ * @param pkt Packet to be inserted in queue
+ * @param pktq Packet queue to insert into
+ * @param prio Priority of packet
+ */
+void cfpkt_queue(cfpktq_t *pktq, cfpkt_t *pkt, unsigned short prio);
+
+/**
+ * Remove a packet from the packet queue.
+ * @param pktq Packet queue to fetch packets from.
+ * @returns dequeued packet.
+ */
+cfpkt_t *cfpkt_dequeue(cfpktq_t *pktq);
+
+/**
+ * Peek into a packet from the packet queue.
+ * @param pktq Packet queue to fetch packets from.
+ * @returns peek'ed packet.
+ */
+cfpkt_t *cfpkt_qpeek(cfpktq_t *pktq);
+
+/**
+ * Initiates the packet queue.
+ * @param pktq Packet queue to fetch packets from.
+ */
+cfpktq_t *cfpkt_queuecreate(void);
+
+/** Put content of packet into buffer for debuging purposes */
+char *cfpkt_log_pkt(cfpkt_t *pkt, char *buf, int buflen);
+
+
+/*! @} */
+#endif				/* CFPKT_H_ */
diff --git a/include/net/caif/generic/cfserl.h b/include/net/caif/generic/cfserl.h
new file mode 100644
index 0000000..e93500d
--- /dev/null
+++ b/include/net/caif/generic/cfserl.h
@@ -0,0 +1,22 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFSERL_H_
+#define CFSERL_H_
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+layer_t *cfserl_create(int type, int instance, bool use_stx);
+
+#endif				/* CFSERL_H_ */
diff --git a/include/net/caif/generic/cfshml.h b/include/net/caif/generic/cfshml.h
new file mode 100644
index 0000000..d7e0247
--- /dev/null
+++ b/include/net/caif/generic/cfshml.h
@@ -0,0 +1,21 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFSHML_H_
+#define CFSHML_H_
+
+layer_t *cfshml_create(int type, int instance);
+
+#endif				/* CFSHML_H_ */
diff --git a/include/net/caif/generic/cfspil.h b/include/net/caif/generic/cfspil.h
new file mode 100644
index 0000000..293e2b5
--- /dev/null
+++ b/include/net/caif/generic/cfspil.h
@@ -0,0 +1,80 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFSPIL_H_
+#define CFSPIL_H_
+#include <net/caif/generic/cfpkt.h>
+#define CAIF_MAX_SPI_FRAME 4096
+
+/* Forward declaration */
+struct _cfspil_t;
+
+typedef struct _cfspil_t cfspil_t;
+
+/** @page SPI PHY Layer description.
+ *
+ *  SPI Physical layer is not implemented in GenCaif. The SPI PHY Layer
+ *  is HW dependent. But the CFSPIL (Caif SPI Layer) provides support for
+ *  implementing the SPI Layer Protocol.
+ *
+ *  SPI PHY uses a different paradigm for transmit than the rest of GenCaif.
+ *  SPI PHY is pulling packets from CFSPIL. The SPI-PHY get a notification
+ *  about a transfer, and then request transfer length, and data to transfer
+ *  in the following way:
+ * \image html caif-spi.jpg "CAIF SPI Flow"
+ *
+ *  -# Wait for transmit request (packet will be \b null pointer) indicating
+ *     GenCaif want something to be sent to the modem.
+ *  -# Request the transfer length by using function \ref cfspil_xmitlen,
+ *  -# Add Caif SPI Command to SPI transfer.
+ *  -# When SPI is ready for transfer, call \ref cfspil_getxmitpkt to get
+ *      the transfer packet.
+ *  -# Request new transfer length ( \ref cfspil_xmitlen) unless zero
+ *     length is returned.
+ *  -# Wait for next transfer request.
+ *
+ *
+ *   * CFSPIL Specification:
+ * \see { GenCaifSPI }
+ *
+ */
+/*! \addtogroup GenCaifSPI
+ *  Additional documentation for group `GenCaifSPI'
+ *  @{
+ */
+
+/** SPI-Layer
+ * Create and initializes SPI layer.
+ */
+layer_t *cfspil_create(int type, int instance);
+
+/**
+ *  Check the length of the next SPI frame to send.
+ *  @param layr Pointer to SPI layer
+ *  @return Length of next SPI transfer, 0 if nothink to  send.
+ */
+int cfspil_xmitlen(cfspil_t *layr);
+
+/**
+ *  Get the next CAIF SPI frame to send. This packet is guaranteed to have equal size to the
+ *  length given in \ref cfspil_getxmitpkt.
+ *  @param layr Pointer to SPI layer
+ *  @return The CAIF Packet to be sent.
+ */
+cfpkt_t *cfspil_getxmitpkt(cfspil_t *layr);
+
+/*! @} */
+
+#endif				/* CFSPIL_H_ */
diff --git a/include/net/caif/generic/cfsrvl.h b/include/net/caif/generic/cfsrvl.h
new file mode 100644
index 0000000..bf25671
--- /dev/null
+++ b/include/net/caif/generic/cfsrvl.h
@@ -0,0 +1,48 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef CFSRVL_H_
+#define CFSRVL_H_
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfglue.h>
+#include <stddef.h>
+
+
+
+typedef struct _cfsrvl_t {
+	layer_t layer;
+	/** Physical ID of the logical physical connection */
+	uint8 phid;
+	bool open;
+	bool phy_flow_on;
+	bool modem_flow_on;
+} cfsrvl_t;
+
+layer_t *cfvei_create(uint8 linkid, uint8 phyid);
+layer_t *cfdgml_create(uint8 linkid, uint8 phyid);
+
+layer_t *cfutill_create(uint8 linkid, uint8 phyid);
+layer_t *cfvidl_create(uint8 linkid, uint8 phyid);
+layer_t *cfrfml_create(uint8 linkid, uint8 phyid);
+bool cfsrvl_phyid_match(layer_t *layer, int phyid);
+void cfservl_destroy(layer_t *layer);
+
+
+void cfsrvl_init(cfsrvl_t *service, uint8 channel_id, uint8 phyid);
+bool cfsrvl_ready(cfsrvl_t *service, int *err);
+uint8 cfsrvl_getphyid(layer_t *layer);
+
+
+#endif				/* CFSRVL_H_ */
diff --git a/include/net/caif/generic/fcs.h b/include/net/caif/generic/fcs.h
new file mode 100644
index 0000000..0b82e2d
--- /dev/null
+++ b/include/net/caif/generic/fcs.h
@@ -0,0 +1,22 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#ifndef FCS_H_
+#define FCS_H_
+
+uint16
+fcs16(uint16 fcs, uint8 *cp, uint16 len);
+
+#endif				/* FCS_H_ */
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 3/8-v2] CAIF Protocol Stack
  2009-10-09 13:39   ` [PATCH] [CAIF-RFC 2/8-v2] " sjur.brandeland
@ 2009-10-09 13:39     ` sjur.brandeland
  2009-10-09 13:39       ` [PATCH] [CAIF-RFC 4/8-v2] " sjur.brandeland
  2009-10-12  9:28     ` [PATCH] [CAIF-RFC 2/8-v2] " Stefano Babic
  1 sibling, 1 reply; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: I63d22d52ce77e51238c842fad8319690d768e791
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 include/net/caif/caif_actions.h     |   75 ++++++++
 include/net/caif/caif_chr.h         |   52 ++++++
 include/net/caif/caif_config_util.h |   27 +++
 include/net/caif/caif_kernel.h      |  324 +++++++++++++++++++++++++++++++++++
 include/net/caif/caif_log.h         |   83 +++++++++
 5 files changed, 561 insertions(+), 0 deletions(-)
 create mode 100644 include/net/caif/caif_actions.h
 create mode 100644 include/net/caif/caif_chr.h
 create mode 100644 include/net/caif/caif_config_util.h
 create mode 100644 include/net/caif/caif_kernel.h
 create mode 100644 include/net/caif/caif_log.h

diff --git a/include/net/caif/caif_actions.h b/include/net/caif/caif_actions.h
new file mode 100644
index 0000000..897f6f8
--- /dev/null
+++ b/include/net/caif/caif_actions.h
@@ -0,0 +1,75 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+#ifndef CAIF_ACTION_H_
+#define CAIF_ACTION_H_
+#include <linux/caif/caif_config.h>
+#include <linux/caif/caif_ioctl.h>
+
+#define DEVICE_NAME_LEN 16
+
+/**
+ * Types of Physical HW Interfaces towards modem defined in CAIF Stack,
+ * used when CAIF enumerates Interfaces and for Channel Configuration.
+ *
+ * For Client convenience to special types are defined:
+ *  - \ref CAIF_PHY_LOW_LAT is the preferred low latency physical link.
+ *         Typically used for "control" purposes.
+ *  - \ref CAIF_PHY_HIGH_BW is the preferred high bandwidth physical link.
+ *         Typically used for "payload" purposes.
+ *  - \ref CAIF_PHY_UNCPECIFIED CAIF Stack implementation will assign link
+ *         for you.
+ *
+ */
+enum caif_phy_type {
+	CAIF_PHY_UNSPECIFIED = 0x00,	/*!< Default Physical Interface */
+	CAIF_PHY_SERIAL = 0x10,	/*!< Serial Physical Interface */
+	CAIF_PHY_SPI = 0x20,	/*!< SPI Physical Interface */
+	CAIF_PHY_MSL = 0x30,	/*!< MSL Physical Interface */
+	CAIF_PHY_SHM = 0x40,	/*!< Shared Memory Interface */
+	CAIF_PHY_LOOP = 0x70,	/*!< Loop-back Interface Simulating ACC side
+				   responses */
+	CAIF_PHY_RAW_LOOP = 0x80,	/*!< Raw loop-back interface */
+};
+#define CAIF_PHY_MASK  0xf0
+
+
+
+
+
+
+/** Query the names of the Enumerated CAIF Physical Interfaces. */
+#define CAIF_ACT_LIST_PHYIFS 	         1	/*struct caif_device_list_action) */
+
+/** Get the physical interface information, given the name. */
+#define CAIF_ACT_GET_PHYIF_INFO 	 2	/*struct caif_phyif_info_action) */
+
+/** Enumerate a physical interface. */
+#define CAIF_ACT_ACTIVATE_PHYIF 		  3	/*struct caif_phy_activate) */
+
+/** Removes (De-Enumerates) a physical interface. */
+#define CAIF_ACT_DEACT_DEVICE 		 4	/*struct caif_device_name) */
+
+/** Get the device names of configured devices */
+#define CAIF_ACT_LIST_DEVICE_NAMES 	  5	/*struct caif_device_list_action) */
+
+/** Get configuration and status information for a specified CAIF device */
+#define CAIF_ACT_GET_DEVICE_INFO  	 6	/*struct caif_device_info_action) */
+
+/** Create and Configure a new CAIF device. Note that the device is not
+ * implicitly connected. */
+
+#define CAIF_ACT_CREATE_DEVICE 		 7 /*struct caif_channel_create_action*/
+
+/** Remove a CAIF device. Requires the device to be previously disconnected. */
+#define CAIF_ACT_DELETE_DEVICE           8	/*struct caif_device_name) */
+
+
+
+#endif
diff --git a/include/net/caif/caif_chr.h b/include/net/caif/caif_chr.h
new file mode 100644
index 0000000..62f1821
--- /dev/null
+++ b/include/net/caif/caif_chr.h
@@ -0,0 +1,52 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+#ifndef CAIF_CHR_H_
+#define CAIF_CHR_H_
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfspil.h>
+#include <linux/caif/caif_config.h>
+#include <net/caif/caif_actions.h>
+struct caif_service_config;
+
+typedef enum _cf_chr_dev_type_t {
+	CFDEVTYPE_CHR,
+	CFDEVTYPE_TTY,
+	CFDEVTYPE_NET
+} cf_chr_dev_type_t;
+
+extern int serial_use_stx;
+
+int caifdev_phy_reg(layer_t *phyif, cfcnfg_phy_mgmt_t *mgmt);
+int caifdev_phy_instanciate(cfcnfg_phy_config_t *phy_config);
+int caifdev_phy_register(layer_t *phyif, cfcnfg_phy_type_t phy_type,
+			 cfcnfg_phy_preference_t phy_pref);
+int caifdev_phy_unregister(layer_t *phyif);
+int caifdev_phy_loop_register(layer_t *phyif, cfcnfg_phy_type_t phy_type);
+int caifdev_phy_spi_xmitlen(cfspil_t *layr);
+cfpkt_t *caifdev_phy_spi_getxmitpkt(cfspil_t *layr);
+int caifdev_adapt_register(struct caif_channel_config *config,
+			   layer_t *adap_layer);
+int caifdev_adapt_unregister(layer_t *adap_layer);
+
+int caif_register_chrdev(int (*chrdev_mgmt)
+			  (int action, union caif_action *param));
+void caif_unregister_chrdev(void);
+
+int caif_register_netdev(int (*netdev_mgmt)
+		     (int action, union caif_action *param));
+void caif_unregister_netdev(void);
+
+#endif				/* CAIF_CHR_H_ */
diff --git a/include/net/caif/caif_config_util.h b/include/net/caif/caif_config_util.h
new file mode 100644
index 0000000..e012079
--- /dev/null
+++ b/include/net/caif/caif_config_util.h
@@ -0,0 +1,27 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+#ifndef CAIF_CONFIG_UTIL_H_
+#define CAIF_CONFIG_UTIL_H_
+
+#include <linux/caif/caif_config.h>
+#include <linux/caif/caif_ioctl.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/caif_actions.h>
+
+int channel_config_2_link_param(cfcnfg_t *cnfg,
+				struct caif_channel_config *s,
+				cfctrl_link_param_t *l);
+
+#endif
diff --git a/include/net/caif/caif_kernel.h b/include/net/caif/caif_kernel.h
new file mode 100644
index 0000000..8fcbd60
--- /dev/null
+++ b/include/net/caif/caif_kernel.h
@@ -0,0 +1,324 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      CAIF Kernel Internal interface for configuring and accessing
+ *      CAIF Channels.
+ *
+ *      Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef CAIF_KERNEL_H_
+#define CAIF_KERNEL_H_
+#include <linux/caif/caif_config.h>
+struct sk_buff;
+
+/*!\page  caif_kernel.h
+ * This is the specification of the CAIF Kernel internal interface to
+ * CAIF Channels.
+ * This interface follows the pattern used in Linux Device Drivers with a
+ *  struct \ref caif_device
+ * holding control data handling each device instance.
+ *
+ * The functional interface consist of a few basic functions:
+ *  - \ref caif_add_device             Configures and Connect the CAIF
+ *               Channel to the remote end. Configuration is described in
+ *               \ref caif_channel_config.
+ *  - \ref caif_remove_device          Disconnect and remove the Channel.
+ *  - \ref caif_transmit               Sends a CAIF message on the link.
+ *  - \ref caif_device.receive_cb      Receive Callback function for
+ *                receiving packets.
+ *  - \ref caif_device.control_cb      Control information from the CAIF stack.
+ *  - \ref caif_flow_control           Send Flow Control mesasge to remote end.
+ *
+ *
+ * Details:
+ * \see { caif_kernel }
+ *
+ * \code
+ *
+#include <net/caif/caif_kernel.h>"
+
+
+static void my_receive(struct caif_device *dev, struct sk_buff *skb)
+{
+...
+}
+
+static void my_control(struct caif_device *dev, enum caif_control ctrl)
+{
+....
+}
+
+int kernel_caif_usage_exampe()
+{
+struct sk_buff *skb;
+char *message = "hello";
+
+
+// Connect the Channel
+struct caif_device caif_dev = {
+.caif_config = {
+.name = "MYDEV",
+.priority = CAIF_PRIO_NORMAL,
+.type = CAIF_CHTY_UTILITY,
+.phy_pref = CAIF_PHYPREF_LOW_LAT,
+.u.utility.name = "CAIF_PSOCK_TEST",
+.u.utility.params = {0x01},
+.u.utility.paramlen = 1,
+},
+
+.receive_cb = my_receive,
+.control_cb = my_control,
+
+};
+ret = caif_add_device(&caif_dev);
+if (ret)
+goto error;
+
+// Send a packet
+skb = caif_create_skb(message, strlen(message));
+ret = caif_transmit(&caif_dev, skb);
+if (ret)
+goto error;
+
+
+// Remove device
+ret = caif_remove_device(&caif_dev);
+if (ret)
+goto error;
+
+}
+
+* \endcode
+*
+* \section Linux Socket Buffer (SKB)
+    *          When sending out packets on a connection (\ref caif_transmit)
+    *          the CAIF stack will add CAIF protocol headers.
+    *          This requires space in the SKB.
+    *          Caif has defined \ref CAIF_SKB_HEAD_RESERVE for minimum
+    *          required reserved head-space in the packet and
+    *          \ref CAIF_SKB_TAIL_RESERVE for minimum reserved tail-space.
+    *
+    *          \b NOTE The Linux kernel SKB operations panics if not
+    *                  enough space is available!
+    *
+    */
+
+    /*! \addtogroup caif_kernel
+     *  @{
+     */
+
+struct caif_device;
+
+
+    /** Minimum required CAIF Socket Buffer head-space */
+#define CAIF_SKB_HEAD_RESERVE 32
+
+    /** Minimum required CAIF Socket Buffer tail-space */
+#define CAIF_SKB_TAIL_RESERVE 32
+
+    /** CAIF Control information (used in \ref caif_device.control_cb)
+     *   used for receiving control information from Modem. */
+enum caif_control {
+	/** Modem has sent Flow-ON, Clients can start transmitting
+	 *  data using \ref caif_transmit. */
+	CAIF_CONTROL_FLOW_ON = 0,
+	/** Modem has sent Flow-OFF, Clients must stop transmitting
+	 * data using \ref caif_transmit. */
+	CAIF_CONTROL_FLOW_OFF = 1,
+
+	/** Channel Creation is complete. This is an acknowledge to
+	 *  (\ref caif_add_device) from Modem.
+	 *  and the Channel is ready for transmit (Flow-state is ON). */
+	CAIF_CONTROL_DEV_INIT = 3,
+
+	/** Spontaneous close request from Modem, only applicable
+	 *   for Utility Link. The Client should respond by calling
+	 *   \ref caif_remove_device */
+	CAIF_CONTROL_REMOTE_SHUTDOWN = 4,
+
+	/** Channel disconnect is complete. This is an acknowledge to
+	 *  (\ref caif_remove_device) from Modem.
+	 *  \ref caif_transmit or \ref caif_flow_control must not be
+	 *  called after this. */
+	CAIF_CONTROL_DEV_DEINIT = 5,
+
+	/** Channel Creation has failed. This is an negative acknowledge
+	 *  to (\ref caif_add_device) from Modem. */
+	CAIF_CONTROL_DEV_INIT_FAILED = 6
+};
+
+
+/** Flow Control information (used in \ref caif_device.control_cb) used
+ *  for controlling outgoing flow */
+enum caif_flowctrl {
+	/** Flow Control is ON, transmit function can start sending data */
+	CAIF_FLOWCTRL_ON = 0,
+	/** Flow Control is OFF, transmit function should stop sending data */
+	CAIF_FLOWCTRL_OFF = 1,
+};
+
+/** Transmits CAIF Packets on Channel.
+ * This function is non-blocking and safe to use in tasklet context.
+ * The CAIF Stack takes ownership of the Socket Buffer (SKB) after calling
+ * \ref caif_transmit.
+ * This means that the user cannot access the SKB afterwards, this applies
+ * even in error situations.
+ *
+ * @return 0 on success, < 0 upon error.
+ *
+ * @param[in] skb         Socket Buffer holding data to be written.
+ * @param[in] dev         Structure used when creating the channel
+ *
+ *
+ * Error codes:
+ *  - \b ENOTCONN,   The Channel is not connected.
+ *  - \b EPROTO,     Protocol error (or skb is faulty)
+ *  - \b EIO         IO Error (unspecified error)
+ */
+int caif_transmit(struct caif_device *dev, struct sk_buff *skb);
+
+
+/** Function for sending flow ON / OFF to remote end.
+ * This function is non-blocking and safe to use in tasklet context.
+ *
+ * @param[in] dev        Reference to device data.
+ * @param[in] flow       Flow Control information.
+
+ * @return 0 on success, < 0 upon error.
+ * Error codes:
+ *  - \b ENOTCONN,   The Channel is not connected.
+ *  - \b EPROTO,     Protocol error.
+ *  - \b EIO         IO Error (unspecified error).
+ */
+int caif_flow_control(struct caif_device *dev, enum caif_flowctrl flow);
+
+
+
+/** Handle for Kernel Internal CAIF Channels.
+ * All fields in this structure must be filled in by Client before calling
+ * \ref caif_add_device (except _caif_handle).
+ */
+struct caif_device {
+
+    /** Channel Configuration Parameter. Contains information about type
+     *	and configuration of the channel.
+     *  This must be set before calling \ref caif_add_device. */
+	struct caif_channel_config caif_config;
+
+
+    /** Callback Function for receiving CAIF Packets from Channel.
+     * This callback is called from softirq context (tasklet).
+     * The receiver <b> must </b> free the skb.
+     * <b> DO NOT BLOCK IN THIS FUNCTION! </b>
+     *
+     * If client has to do blocking operations
+     * it must start it's own work queue (or kernel thread).
+     *
+     * @param[in] dev        Reference to device data.
+     * @param[in] skb       Socket Buffer with received data.
+     */
+	void (*receive_cb) (struct caif_device *dev, struct sk_buff *skb);
+
+
+    /** Callback Function for notifying flow control from remote end see
+     *  \ref caif_control.
+     * This callback is called from from softirq context (tasklet).
+     *
+     * <b> DO NOT BLOCK IN THIS FUNCTION! </b>
+     *
+     * Client must not call \ref caif_transmit from this function.
+     *
+     * If client has queued packets to send
+     * it must start its own thread to do \ref caif_transmit from.
+     *
+     * @param[in] dev        Reference to device data.
+     * @param[in] ctrl       CAIF Control info \ref caif_control.
+     *                       e.g. Flow control
+     *                       \ref CAIF_CONTROL_FLOW_ON or
+     *                       \ref CAIF_CONTROL_FLOW_OFF
+     *
+     */
+	void (*control_cb) (struct caif_device *dev, enum caif_control ctrl);
+
+    /** This is a CAIF private attribute, holding CAIF internal reference
+     * to the CAIF stack. Do not update this field */
+
+	void *_caif_handle;
+
+    /** This field may be filled in by Client for their own usage. */
+	void *user_data;
+};
+
+
+
+/** Add (Connects) a CAIF Channel.
+ * This function is non-blocking. The channel connect is reported in
+ * \ref caif_device.control_cb.
+ * The channel is not open until \ref caif_device.control_cb is called with
+ * \ref CAIF_CONTROL_DEV_INIT.
+ * If setting up the channel fails \ref caif_device.control_cb is called with
+ * \ref CAIF_CONTROL_DEV_INIT_FAILED.
+ *
+ * \ref caif_transmit, \ref caif_flow_control or \ref caif_remove_device must
+ * not be called before receiveing CAIF_CONTROL_DEV_INIT.
+ * @return 0 on success, < 0 on failure.
+ *
+ * Error codes:
+ * - \b -EINVAL    Invalid Arguments
+ * - \b -ENODEV    No PHY Device exists.
+ * - \b -EIO       IO Error (unspecified error)
+ *
+ */
+int caif_add_device(struct caif_device *dev);
+
+
+
+/** Disconnect a CAIF Channel
+ * This function is non-blocking.
+ * The channel is not disconnected until \ref caif_device : control_cb is
+ * called with \ref CAIF_CONTROL_DEV_DEINIT.
+ * \ref caif_transmit or \ref caif_flow_control \b must not be called after
+ * receiving \ref CAIF_CONTROL_DEV_DEINIT.
+ * The Client is responsible for freeing the \ref caif_device structure after
+ * receiving  \ref CAIF_CONTROL_DEV_DEINIT (if applicable).
+ * @return 0 on success.
+ *
+ * - \b EIO       IO Error (unspecified error)
+ *
+ */
+int caif_remove_device(struct caif_device *caif_dev);
+
+
+
+/** Convenience function for allocating a socket buffer for usage with CAIF
+ * and copy user data into the socket buffer.
+ * @param[in] data User data to send with CAIF.
+ * @param[in] data_length of data to send.
+ * @return socket buffer .
+ *
+ */
+struct sk_buff *caif_create_skb(unsigned char *data, unsigned int data_length);
+
+
+/** Convenience function for extracting data from a socket buffer (SKB) and
+ *  then destroy it.
+ *  Copies data from the SKB frees the SKB.
+ * @param[in] skb SKB to extract data from. SKB will be freed after extracting
+ *            data.
+ *
+ * @param[in] data User data buffer to extract packet data into.
+ * @param[in] max_length User data buffer length,
+ * @return number of bytes extracted; < 0 upon error.
+ *
+ */
+int caif_extract_and_destroy_skb(struct sk_buff *skb, unsigned char *data,
+				 unsigned int max_length);
+
+
+
+/*! @} */
+
+#endif				/* CAIF_KERNEL_H_ */
diff --git a/include/net/caif/caif_log.h b/include/net/caif/caif_log.h
new file mode 100644
index 0000000..d62770e
--- /dev/null
+++ b/include/net/caif/caif_log.h
@@ -0,0 +1,83 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+#ifndef CAIF_LOG_H_
+#define CAIF_LOG_H_
+
+extern int caif_dbg_level;
+
+#define CAIFLOG_ON 1
+
+#define CAIFLOG_MIN_LEVEL     1
+#define CAIFLOG_LEVEL_ERROR   1
+#define CAIFLOG_LEVEL_WARNING 2
+#define CAIFLOG_LEVEL_TRACE   3
+#define CAIFLOG_LEVEL_TRACE2  4
+#define CAIFLOG_LEVEL_TRACE3  5
+#define CAIFLOG_LEVEL_FUNC    6
+#define CAIFLOG_MAX_LEVEL     6
+
+/** Fatal error condition, halt the kernel */
+#define CAIFLOG_FATAL(format, args...) do if ( \
+	caif_dbg_level > CAIFLOG_LEVEL_ERROR)  \
+	printk(KERN_ERR "<%s:%d, FATAL> " format, __func__, __LINE__ , \
+	## args);\
+  while (0)
+
+/** CAIF Error Logging. */
+#define CAIFLOG_ERROR(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_ERROR)  \
+printk(KERN_ERR "<%s:%d, ERROR> " format, __func__, __LINE__ , ## args);\
+  while (0)
+
+/** CAIF Warning Logging. */
+#define CAIFLOG_WARN(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_WARNING)	 \
+printk(KERN_WARNING "<%s:%d, WARN> "  format, __func__, __LINE__ , ## args);\
+  while (0)
+
+/** CAIF Trace Control Logging. Level 1 control trace (Channel setup etc) */
+#define CAIFLOG_TRACE(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_TRACE)  \
+printk(KERN_WARNING "<%s:%d, TRACE> " format, __func__, __LINE__ , ## args); \
+ while (0)
+
+/** CAIF Trace Payload Logging. Level payload trace */
+#define CAIFLOG_TRACE2(format, args...) do if ( \
+caif_dbg_level > CAIFLOG_LEVEL_TRACE2)	\
+printk(KERN_WARNING "<%s:%d, TRACE2> " format, __func__, __LINE__ , ## args);\
+  while (0)
+
+/** CAIF Trace Detailed Logging including packet dumps */
+#define CAIFLOG_TRACE3(format, args...) do if ( \
+caif_dbg_level > CAIFLOG_LEVEL_TRACE3)	\
+printk(KERN_WARNING "<%s:%d, TRACE3> " format, __func__, __LINE__ , ## args); \
+ while (0)
+
+/** CAIF Trace Entering Function */
+#define CAIFLOG_ENTER(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_FUNC)  \
+printk(KERN_WARNING "<%s:%d, ENTER> " format, __func__, __LINE__ , ## args); \
+ while (0)
+
+/** CAIF Trace Exiting Function */
+#define CAIFLOG_EXIT(format, args...)	do if (\
+caif_dbg_level > CAIFLOG_LEVEL_FUNC)  \
+printk(KERN_WARNING "<%s:%d, EXIT> "  format, __func__, __LINE__ , ## args);\
+  while (0)
+
+#define IF_CAIF_TRACE(cmd) do if (\
+caif_dbg_level > CAIFLOG_LEVEL_TRACE) { cmd; } \
+  while (0)
+
+#endif				/*CAIF_LOG_H_ */
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 4/8-v2] CAIF Protocol Stack
  2009-10-09 13:39     ` [PATCH] [CAIF-RFC 3/8-v2] " sjur.brandeland
@ 2009-10-09 13:39       ` sjur.brandeland
  2009-10-09 13:39         ` [PATCH] [CAIF-RFC 5/8-v2] " sjur.brandeland
  2009-10-12 12:20         ` [PATCH] [CAIF-RFC 4/8-v2] " Stefano Babic
  0 siblings, 2 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: Ifa7d1709f212dd29519fdfa42bcfba801fcf173b
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 net/caif/generic/cfcnfg.c       |  546 ++++++++++++++++++++++++++++++++
 net/caif/generic/cfctrl.c       |  666 +++++++++++++++++++++++++++++++++++++++
 net/caif/generic/cfdgml.c       |  119 +++++++
 net/caif/generic/cffrml.c       |  146 +++++++++
 net/caif/generic/cflist.c       |   99 ++++++
 net/caif/generic/cfloopcfg.c    |   93 ++++++
 net/caif/generic/cflooplayer.c  |  116 +++++++
 net/caif/generic/cfmsll.c       |   55 ++++
 net/caif/generic/cfmuxl.c       |  258 +++++++++++++++
 net/caif/generic/cfpkt_plain.c  |  557 ++++++++++++++++++++++++++++++++
 net/caif/generic/cfpkt_skbuff.c |  585 ++++++++++++++++++++++++++++++++++
 net/caif/generic/cfrfml.c       |  112 +++++++
 net/caif/generic/cfserl.c       |  297 +++++++++++++++++
 net/caif/generic/cfshml.c       |   67 ++++
 net/caif/generic/cfspil.c       |  245 ++++++++++++++
 net/caif/generic/cfsrvl.c       |  177 +++++++++++
 net/caif/generic/cfutill.c      |  115 +++++++
 net/caif/generic/cfveil.c       |  118 +++++++
 net/caif/generic/cfvidl.c       |   68 ++++
 net/caif/generic/fcs.c          |   58 ++++
 20 files changed, 4497 insertions(+), 0 deletions(-)
 create mode 100644 net/caif/generic/cfcnfg.c
 create mode 100644 net/caif/generic/cfctrl.c
 create mode 100644 net/caif/generic/cfdgml.c
 create mode 100644 net/caif/generic/cffrml.c
 create mode 100644 net/caif/generic/cflist.c
 create mode 100644 net/caif/generic/cfloopcfg.c
 create mode 100644 net/caif/generic/cflooplayer.c
 create mode 100644 net/caif/generic/cfmsll.c
 create mode 100644 net/caif/generic/cfmuxl.c
 create mode 100644 net/caif/generic/cfpkt_plain.c
 create mode 100644 net/caif/generic/cfpkt_skbuff.c
 create mode 100644 net/caif/generic/cfrfml.c
 create mode 100644 net/caif/generic/cfserl.c
 create mode 100644 net/caif/generic/cfshml.c
 create mode 100644 net/caif/generic/cfspil.c
 create mode 100644 net/caif/generic/cfsrvl.c
 create mode 100644 net/caif/generic/cfutill.c
 create mode 100644 net/caif/generic/cfveil.c
 create mode 100644 net/caif/generic/cfvidl.c
 create mode 100644 net/caif/generic/fcs.c

diff --git a/net/caif/generic/cfcnfg.c b/net/caif/generic/cfcnfg.c
new file mode 100644
index 0000000..3aad201
--- /dev/null
+++ b/net/caif/generic/cfcnfg.c
@@ -0,0 +1,546 @@
+/*
+ *	Copyright (C) ST-Ericsson AB 2009
+ *
+ *	Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfmuxl.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/generic/cfserl.h>
+#include <net/caif/generic/cfspil.h>
+#include <net/caif/generic/cfshml.h>
+#include <net/caif/generic/cfmsll.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cffrml.h>
+
+#define MAX_PHY_LAYERS 7
+#define PHY_NAME_LEN 20
+
+#define container_obj(layr) cfglu_container_of(layr, cfcnfg_t, layer)
+
+
+/* Information about CAIF physical interfaces held by Config Module in order
+   to manage physical interfaces */
+
+struct cfcnfg_phyinfo {
+	/** Type of physical layer e.g. UART or SPI */
+	cfcnfg_phy_type_t type;
+	/** Pointer to the layer below the MUX (framing layer) */
+	layer_t *frm_layer;
+	/** Pointer to the lowest actual physical layer */
+	layer_t *phy_layer;
+	/** Unique identifier of the physical interface */
+	unsigned int id;
+	/** Name of the physical interface */
+	char name[PHY_NAME_LEN];
+	/** Preference of the physical in interface */
+	cfcnfg_phy_preference_t pref;
+
+	/** Reference count, number of channels using the device */
+	int phy_ref_count;
+};
+
+
+struct _cfcnfg_t {
+	layer_t layer;
+	layer_t *ctrl;
+	layer_t *mux;
+	uint8 last_phyid;
+	struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS];
+	cfcnfg_phy_mgmt_t phy_registration[_CFPHYTYPE_MAX];
+};
+
+/**
+ * This variable is used as a global flag in order to set if STX is used on serial communication.
+ *  NOTE: This is not a fully future proof solution.
+ */
+
+int serial_use_stx;
+
+static void cncfg_linkup_rsp(layer_t *layer, uint8 linkid,
+			     cfctrl_srv_t serv, uint8 phyid,
+			     layer_t *adapt_layer);
+static void cncfg_linkdestroy_rsp(layer_t *layer, uint8 linkid,
+				  layer_t *client_layer);
+static void cncfg_reject_rsp(layer_t *layer, uint8 linkid,
+			     layer_t *adapt_layer);
+static void cfctrl_resp_func(void);
+static void cfctrl_enum_resp(void);
+
+
+
+cfcnfg_t *cfcnfg_create()
+{
+
+	cfcnfg_t *this;
+	cfctrl_rsp_t resp;
+	/* Initiate response functions */
+	resp.enum_rsp = cfctrl_enum_resp;
+	resp.linkerror_ind = cfctrl_resp_func;
+	resp.linkdestroy_rsp = cncfg_linkdestroy_rsp;
+	resp.sleep_rsp = cfctrl_resp_func;
+	resp.wake_rsp = cfctrl_resp_func;
+	resp.restart_rsp = cfctrl_resp_func;
+	resp.radioset_rsp = cfctrl_resp_func;
+	resp.linksetup_rsp = cncfg_linkup_rsp;
+	resp.reject_rsp = cncfg_reject_rsp;
+	/* Initiate this layer */
+	this = cfglu_alloc(sizeof(cfcnfg_t));
+	memset(this, 0, sizeof(cfcnfg_t));
+	this->mux = cfmuxl_create();
+	this->ctrl = cfctrl_create();
+	this->last_phyid = 1;
+	cfctrl_set_respfuncs(this->ctrl, &resp);
+	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
+	layer_set_dn(this->ctrl, this->mux);
+	layer_set_up(this->ctrl, this);
+	return this;
+}
+
+static void cfctrl_resp_func(void)
+{
+	CFLOG_ENTER(("cfcnfg: cfctrl_resp_func\n"));
+	CFLOG_EXIT(("cfcnfg: cfctrl_resp_func\n"));
+}
+
+static void cfctrl_enum_resp(void)
+{
+	CFLOG_ENTER(("cfcnfg: enter cfctrl_enum_resp\n"));
+	CFLOG_EXIT(("cfcnfg: exit cfctrl_enum_resp\n"));
+}
+
+
+int cfcnfg_get_phyid(cfcnfg_t *cnfg, cfcnfg_phy_preference_t phy_pref)
+{
+	int i;
+
+	/* Try to match with specified preference */
+	for (i = 1; i < MAX_PHY_LAYERS; i++) {
+		if (cnfg->phy_layers[i].id == i &&
+		     cnfg->phy_layers[i].pref == phy_pref &&
+		     cnfg->phy_layers[i].frm_layer != NULL) {
+			cfglu_assert(cnfg->phy_layers != NULL);
+			cfglu_assert(cnfg->phy_layers[i].id == i);
+			return cnfg->phy_layers[i].frm_layer->id;
+		}
+	}
+	/* Otherwise just return something */
+	for (i = 1; i < MAX_PHY_LAYERS; i++) {
+		if (cnfg->phy_layers[i].id == i) {
+			cfglu_assert(cnfg->phy_layers != NULL);
+			cfglu_assert(cnfg->phy_layers[i].id == i);
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(cfcnfg_t *cnfg, uint8 phyid)
+{
+	int i;
+
+	/* Try to match with specified preference */
+	for (i = 0; i < MAX_PHY_LAYERS; i++)
+		if (cnfg->phy_layers[i].frm_layer != NULL &&
+		    cnfg->phy_layers[i].id == phyid)
+			return &cnfg->phy_layers[i];
+
+	return 0;
+}
+
+int cfcnfg_get_named(cfcnfg_t *cnfg, char *name)
+{
+	int i;
+
+	/* Try to match with specified preference */
+	for (i = 0; i < MAX_PHY_LAYERS; i++) {
+		if (cnfg->phy_layers[i].frm_layer != NULL
+		    && strcmp(cnfg->phy_layers[i].frm_layer->name,
+			      name) == 0) {
+			return cnfg->phy_layers[i].frm_layer->id;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * NOTE: What happends destroy failure:
+ *	 1a) No response - Too early
+ *	      This will not happend because enumerate has already
+ *	      completed
+ *	 1b) No response - FATAL
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	      Modem error, response is really expected -  this
+ *	      case is not really handled..
+ *	 2) O/E-bit indicate error
+ *	      Ignored - this link is destroyed anyway.
+ *	 3) Not able to match on reques
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	 4) Link-Error - (no response)
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ */
+
+
+bool cfcnfg_del_adapt_layer(struct _cfcnfg_t *cnfg, layer_t *adap_layer)
+{
+	uint8 channel_id = 0;
+	struct cfcnfg_phyinfo *phyinfo = NULL;
+	uint8 phyid = 0;
+	CFLOG_TRACE(("cfcnfg: enter del_adaptation_layer\n"));
+
+	cfglu_assert(adap_layer != NULL);
+	channel_id = adap_layer->id;
+	cfglu_assert(channel_id != 0);
+
+	if (adap_layer->dn == NULL) {
+		CFLOG_ERROR(("cfcnfg:adap_layer->dn is NULL\n"));
+		return CFGLU_EINVAL;
+	}
+
+	if (cnfg->mux != NULL)
+		phyid = cfsrvl_getphyid(adap_layer->dn);
+
+
+	phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
+
+	cfglu_assert(phyinfo != NULL);
+	cfglu_assert(phyinfo->id == phyid);
+	cfglu_assert(phyinfo->phy_layer->id == phyid);
+	cfglu_assert(phyinfo->frm_layer->id == phyid);
+
+	if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
+	    phyinfo->phy_layer->modemcmd != NULL) {
+
+		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
+					     _CAIF_MODEMCMD_PHYIF_USELESS);
+	}
+
+
+	cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
+	return true;
+}
+
+static void cncfg_linkdestroy_rsp(layer_t *layer, uint8 linkid,
+				  layer_t *client_layer)
+{
+	cfcnfg_t *cnfg = container_obj(layer);
+	layer_t *servl;
+
+	CFLOG_TRACE(("cfcnfg: enter linkdestroy_rsp\n"));
+
+	/* 1) Remove service from the MUX layer */
+	servl = cfmuxl_remove_uplayer(cnfg->mux, linkid);
+	/* invar: MUX guarantees not more payload sent "upwards" (receive) */
+
+	if (servl == NULL) {
+		CFLOG_ERROR(("cfcnfg: Error removing service_layer Linkid(%d)",
+			     linkid));
+		return;
+	}
+	cfglu_assert(linkid == servl->id);
+
+	if (servl != client_layer && servl->up != client_layer) {
+		CFLOG_ERROR(("cfcnfg: Error removing service_layer "
+			     "Linkid(%d) %p %p",
+			     linkid, (void *) servl, (void *) client_layer));
+		return;
+	}
+
+	/* 2) SHUTDOWN must guarantee that no more packets are transmitted
+	   from adap_layer when it returns.  We assume it locks the layer for
+	   every transmit and lock when receiving this SHUTDOWN */
+
+	if (servl->ctrlcmd == NULL) {
+		CFLOG_ERROR(("cfcnfg: Error servl->ctrlcmd == NULL"));
+		return;
+	}
+
+	servl->ctrlcmd(servl, CAIF_CTRLCMD_DEINIT_RSP, 0);
+
+	/* invar: Adaptation Layer guarantees not more payload sen
+	   "down-wards" (transmit) */
+
+	/* 3) It is now safe to destroy the service layer (if any) */
+
+	/*
+	 * FIXME: We need a ref-count in order to safely free
+	 *        the up layer.
+	 */
+	if (client_layer != servl->up)
+		cfservl_destroy(servl);
+}
+
+/*
+ * NOTE: What happends linksetup failure:
+ *	 1a) No response - Too early
+ *	      This will not happend because enumerate is secured
+ *	      before using interface)
+ *	 1b) No response - FATAL
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	      Modem error, response is really expected -  this case is
+ *	      not really handled..
+ *	 2) O/E-bit indicate error
+ *	      Handeled in cnfg_reject_rsp
+ *	 3) Not able to match on reques
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ *	 4) Link-Error - (no response)
+ *	      Not handled, but this should be a CAIF PROTOCOL ERROR
+ */
+
+bool
+cfcnfg_add_adaptation_layer(cfcnfg_t *cnfg, cfctrl_link_param_t *param,
+			    layer_t *adap_layer)
+{
+	layer_t *frml;
+	CFLOG_TRACE(("cfcnfg[%p]: enter add_adaptation_layer\n",
+		     (void *) cnfg));
+
+	if (adap_layer == NULL) {
+		CFLOG_ERROR(("cfcnfg: adap_layer is zero"));
+		return CFGLU_EINVAL;
+	}
+	if (adap_layer->receive == NULL) {
+		CFLOG_ERROR(("cfcnfg-add: adap_layer->receive is NULL"));
+		return CFGLU_EINVAL;
+	}
+	if (adap_layer->ctrlcmd == NULL) {
+		CFLOG_ERROR(("cfcnfg-add: adap_layer->ctrlcmd == NULL"));
+		return CFGLU_EINVAL;
+	}
+
+	frml = cnfg->phy_layers[param->phyid].frm_layer;
+	if (frml == NULL) {
+		CFLOG_ERROR(("cfcnfg: Specified PHY type does not exist!"));
+		return false;
+	}
+	cfglu_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
+	cfglu_assert(cnfg->phy_layers[param->phyid].frm_layer->id ==
+		     param->phyid);
+	cfglu_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
+		     param->phyid);
+	CFLOG_TRACE(("cfcnfg: send enum request\n"));
+	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
+
+	cfctrl_enum_req(cnfg->ctrl, param->phyid);
+
+	cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
+
+	return true;
+}
+
+static void cncfg_reject_rsp(layer_t *layer, uint8 linkid,
+			     layer_t *adapt_layer)
+{
+	CFLOG_ENTER(("layer=%p linkid=%d adapt_layer=%p\n", (void *) layer,
+		     linkid, (void *) adapt_layer));
+	if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
+		adapt_layer->ctrlcmd(adapt_layer,
+				     CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
+
+}
+
+static void
+cncfg_linkup_rsp(layer_t *layer, uint8 linkid, cfctrl_srv_t serv,
+		 uint8 phyid, layer_t *adapt_layer)
+{
+	cfcnfg_t *cnfg = container_obj(layer);
+	layer_t *servicel = NULL;
+	struct cfcnfg_phyinfo *phyinfo;
+	CFLOG_ENTER(("cfcnfg[%p]: enter scfcnfg_linup_rsp\n", (void *) layer));
+	if (adapt_layer == NULL) {
+		CFLOG_ERROR(("cfcnfg: CAIF PROTOCOL ERROR "
+			     "- LinkUp Request/Response did not match\n"));
+		return;
+	}
+
+	cfglu_assert(cnfg != NULL);
+	cfglu_assert(phyid != 0);
+	phyinfo = &cnfg->phy_layers[phyid];
+	cfglu_assert(phyinfo->id == phyid);
+	cfglu_assert(phyinfo->phy_layer->id == phyid);
+
+	if (phyinfo != NULL &&
+	    phyinfo->phy_ref_count++ == 0 &&
+	    phyinfo->phy_layer != NULL &&
+	    phyinfo->phy_layer->modemcmd != NULL) {
+		cfglu_assert(phyinfo->phy_layer->id == phyid);
+		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
+					     _CAIF_MODEMCMD_PHYIF_USEFULL);
+
+	}
+	adapt_layer->id = linkid;
+
+	switch (serv) {
+	case CFCTRL_SRV_VEI:
+		servicel = cfvei_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: AT channel created\n"));
+		break;
+	case CFCTRL_SRV_DATAGRAM:
+		servicel = cfdgml_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: Datagram channel created\n"));
+		break;
+	case CFCTRL_SRV_RFM:
+		servicel = cfrfml_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: RFM channel created\n"));
+		break;
+	case CFCTRL_SRV_UTIL:
+		servicel = cfutill_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: Utility channel created\n"));
+		break;
+	case CFCTRL_SRV_VIDEO:
+		servicel = cfvidl_create(linkid, phyid);
+		CFLOG_TRACE(("cfcnfg: Video channel created\n"));
+		break;
+	case CFCTRL_SRV_DBG:
+		CFLOG_TRACE(("cfcnfg: Debug channel created\n"));
+		servicel = adapt_layer;
+		break;
+	default:
+		CFLOG_ERROR(("cfcnfg: ERROR "
+			     "Link setup response - unknown channel type\n"));
+		return;
+	}
+	layer_set_dn(servicel, cnfg->mux);
+
+	CFLOG_TRACE(("cfcnfg: insert service layer in mux\n"));
+
+	cfmuxl_set_uplayer(cnfg->mux, servicel, linkid);
+	if (servicel != adapt_layer) {
+		CFLOG_TRACE(("cfcnfg: insert adapt-layer in service layer\n"));
+		layer_set_up(servicel, adapt_layer);
+		layer_set_dn(adapt_layer, servicel);
+	}
+	CFLOG_TRACE(("cfcnfg: successfull link setup - call flowtrl(init)\n"));
+	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
+}
+
+
+
+
+
+caif_packet_funcs_t cfcnfg_get_packet_funcs()
+{
+	return cfpkt_get_packet_funcs();
+}
+
+
+void
+cfcnfg_add_phy_layer(cfcnfg_t *cnfg, cfcnfg_phy_type_t phy_type,
+		     layer_t *phy_layer, uint16 *phyid,
+		     cfcnfg_phy_preference_t pref)
+{
+	layer_t *frml;
+	layer_t *phy_driver = NULL;
+	int i;
+	bool DoFCS = false;
+	CFLOG_TRACE(("cfcnfg: enter add_phy_layer\n"));
+
+	if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) {
+		*phyid = cnfg->last_phyid;
+
+		/* range: * 1..(MAX_PHY_LAYERS-1) */
+		cnfg->last_phyid =
+		    (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1;
+	} else {
+		*phyid = 0;
+		for (i = 1; i < MAX_PHY_LAYERS; i++) {
+			if (cnfg->phy_layers[i].frm_layer == NULL) {
+				*phyid = i;
+				break;
+			}
+		}
+	}
+	if (*phyid == 0) {
+		CFLOG_ERROR(("cfcnfg: No Available PHY ID\n"));
+		return;
+	}
+
+	switch (phy_type) {
+	case CFPHYTYPE_SERIAL:
+		CFLOG_TRACE(("cfcnfg: Starting Serial link\n"));
+		DoFCS = true;
+		phy_driver =
+		    cfserl_create(CFPHYTYPE_SERIAL, *phyid, serial_use_stx);
+		break;
+	case CFPHYTYPE_SPI:
+		CFLOG_TRACE(("cfcnfg: Starting SPI link\n"));
+		phy_driver = cfspil_create(CFPHYTYPE_SPI, *phyid);
+		break;
+	case CFPHYTYPE_SHM:
+		CFLOG_TRACE(("cfcnfg: Starting SHM link\n"));
+		phy_driver = cfshml_create(CFPHYTYPE_SHM, *phyid);
+		break;
+	case CFPHYTYPE_MSL:
+		CFLOG_TRACE(("cfcnfg: Starting MSL link\n"));
+		phy_driver = cfmsll_create(CFPHYTYPE_MSL, *phyid);
+		break;
+	default:
+		CFLOG_ERROR(("cfcnfg: Bad phy_type specified: %d", phy_type));
+		return;
+		break;
+	}
+
+
+	phy_layer->id = *phyid;
+	phy_driver->id = *phyid;
+	cnfg->phy_layers[*phyid].pref = pref;
+	cnfg->phy_layers[*phyid].id = *phyid;
+	cnfg->phy_layers[*phyid].type = phy_type;
+	cnfg->phy_layers[*phyid].phy_layer = phy_layer;
+	cnfg->phy_layers[*phyid].phy_ref_count = 0;
+	phy_layer->type = phy_type;
+	frml = cffrml_create(*phyid, DoFCS);
+	cnfg->phy_layers[*phyid].frm_layer = frml;
+	cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
+	layer_set_up(frml, cnfg->mux);
+	layer_set_dn(frml, phy_driver);
+	layer_set_up(phy_driver, frml);
+	layer_set_dn(phy_driver, phy_layer);
+	layer_set_up(phy_layer, phy_driver);
+	CFLOG_TRACE(("cfcnfg: phy1=%p phy2=%p transmit=0x%d\n",
+		     (void *) phy_driver, (void *) phy_layer,
+		     (int) phy_layer->transmit));
+}
+
+int cfcnfg_del_phy_layer(struct _cfcnfg_t *cnfg, layer_t *phy_layer)
+{
+	layer_t *frml, *cfphy;
+	uint16 phyid;
+	phyid = phy_layer->id;
+	cfglu_assert(phyid == cnfg->phy_layers[phyid].id);
+	cfglu_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer);
+	cfglu_assert(phy_layer->id == phyid);
+	cfglu_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid);
+
+	memset(&cnfg->phy_layers[phy_layer->id], 0,
+	       sizeof(struct cfcnfg_phyinfo));
+	frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
+	cfphy = frml->dn;
+
+	cffrml_set_uplayer(frml, NULL);
+	cffrml_set_dnlayer(frml, NULL);
+	cffrml_destroy(frml);
+
+	cfglu_assert(cfphy->dn == phy_layer);
+	layer_set_up(cfphy, NULL);
+	layer_set_dn(cfphy, NULL);
+	cfglu_free(cfphy);
+
+	layer_set_up(phy_layer, NULL);
+	return CFGLU_EOK;
+}
diff --git a/net/caif/generic/cfctrl.c b/net/caif/generic/cfctrl.c
new file mode 100644
index 0000000..832559b
--- /dev/null
+++ b/net/caif/generic/cfctrl.c
@@ -0,0 +1,666 @@
+/*
+ *	Copyright (C) ST-Ericsson AB 2009
+ *
+ *	Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfctrl.h>
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfctrl, serv.layer)
+#define UTILITY_NAME_LENGTH 16
+#define CFPKT_CTRL_PKT_LEN 20
+
+
+struct cfctrl {
+	cfsrvl_t serv;
+	cfctrl_rsp_t res;
+	cfglu_atomic_t req_seq_no;
+	cfglu_atomic_t rsp_seq_no;
+	struct cfctrl_request_info *first_req;
+	cfglu_lock_t info_list_lock;
+};
+
+
+static int cfctrl_recv(struct cfctrl *cfctrl, cfpkt_t *pkt);
+static void cfctrl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid);
+
+layer_t *cfctrl_create()
+{
+	struct cfctrl *this =
+	    (struct cfctrl *) cfglu_alloc(sizeof(struct cfctrl));
+	cfglu_assert(offsetof(struct cfctrl, serv.layer) == 0);
+	memset(this, 0, sizeof(*this));
+	cfglu_init_lock(this->info_list_lock);
+	cfglu_atomic_set(this->req_seq_no, 1);
+	cfglu_atomic_set(this->rsp_seq_no, 1);
+	this->serv.phid = 0xff;
+	this->serv.layer.id = 0;
+	this->serv.layer.receive = (receive_cb_t) cfctrl_recv;
+	sprintf(this->serv.layer.name, "ctrl");
+	this->serv.layer.ctrlcmd = cfctrl_ctrlcmd;
+	return &this->serv.layer;
+}
+
+
+bool param_eq(cfctrl_link_param_t *p1, cfctrl_link_param_t *p2)
+{
+	bool eq =
+	    p1->linktype == p2->linktype &&
+	    p1->priority == p2->priority &&
+	    p1->phyid == p2->phyid &&
+	    p1->endpoint == p2->endpoint && p1->chtype == p2->chtype;
+
+	if (!eq)
+		return false;
+
+	switch (p1->linktype) {
+	case CFCTRL_SRV_VEI:
+		return true;
+	case CFCTRL_SRV_DATAGRAM:
+		return p1->u.datagram.connid == p2->u.datagram.connid;
+	case CFCTRL_SRV_RFM:
+		return
+		    p1->u.rfm.connid == p2->u.rfm.connid &&
+		    strcmp(p1->u.rfm.volume, p2->u.rfm.volume) == 0;
+	case CFCTRL_SRV_UTIL:
+		return
+		    p1->u.utility.fifosize_kb == p2->u.utility.fifosize_kb
+		    && p1->u.utility.fifosize_bufs ==
+		    p2->u.utility.fifosize_bufs
+		    && strcmp(p1->u.utility.name, p2->u.utility.name) == 0
+		    && p1->u.utility.paramlen == p2->u.utility.paramlen
+		    && memcmp(p1->u.utility.params, p2->u.utility.params,
+			      p1->u.utility.paramlen) == 0;
+
+	case CFCTRL_SRV_VIDEO:
+		return p1->u.video.connid == p2->u.video.connid;
+	case CFCTRL_SRV_DBG:
+		return true;
+	case CFCTRL_SRV_DECM:
+		return false;
+	default:
+		return false;
+	}
+	return false;
+}
+
+static bool cfctrl_req_eq(struct cfctrl_request_info *r1,
+		   struct cfctrl_request_info *r2)
+{
+	if (r1->cmd != r2->cmd)
+		return false;
+	if (r1->cmd == CFCTRL_CMD_LINK_SETUP)
+		return param_eq(&r1->param, &r2->param);
+	else
+		return r1->channel_id == r2->channel_id;
+}
+
+/* Insert request at the end */
+static void cfctrl_insert_req(struct cfctrl *ctrl,
+			      struct cfctrl_request_info *req)
+{
+	struct cfctrl_request_info *p;
+	cfglu_lock(ctrl->info_list_lock);
+	req->next = NULL;
+	cfglu_atomic_inc(ctrl->req_seq_no);
+	req->sequence_no = cfglu_atomic_read(ctrl->req_seq_no);
+	if (ctrl->first_req == NULL) {
+		ctrl->first_req = req;
+		cfglu_unlock(ctrl->info_list_lock);
+		return;
+	}
+	p = ctrl->first_req;
+	while (p->next != NULL)
+		p = p->next;
+	p->next = req;
+	cfglu_unlock(ctrl->info_list_lock);
+}
+
+static void cfctrl_insert_req2(struct cfctrl *ctrl, cfctrl_cmd_t cmd,
+			       uint8 linkid, layer_t *user_layer)
+{
+	struct cfctrl_request_info *req = cfglu_alloc(sizeof(*req));
+	req->client_layer = user_layer;
+	req->cmd = cmd;
+	req->channel_id = linkid;
+	cfctrl_insert_req(ctrl, req);
+}
+
+/* Compare and remove request */
+struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
+					      struct cfctrl_request_info *req)
+{
+	struct cfctrl_request_info *p;
+	struct cfctrl_request_info *ret;
+
+	cfglu_lock(ctrl->info_list_lock);
+	if (ctrl->first_req == NULL) {
+		cfglu_unlock(ctrl->info_list_lock);
+		return NULL;
+	}
+
+	if (cfctrl_req_eq(req, ctrl->first_req)) {
+		ret = ctrl->first_req;
+		cfglu_atomic_set(ctrl->rsp_seq_no,
+				 ctrl->first_req->sequence_no);
+		ctrl->first_req = ctrl->first_req->next;
+		cfglu_unlock(ctrl->info_list_lock);
+		return ret;
+	}
+
+	CFLOG_WARN(("cfctrl: Requests are not received in order/matching\n"));
+
+	p = ctrl->first_req;
+
+	while (p->next != NULL) {
+		if (cfctrl_req_eq(req, p->next)) {
+			ret = p->next;
+			cfglu_atomic_set(ctrl->rsp_seq_no,
+					 p->next->sequence_no);
+			p = p->next;
+			return ret;
+		}
+		p = p->next;
+	}
+	cfglu_unlock(ctrl->info_list_lock);
+	return NULL;
+}
+
+/* Compare and remove old requests based on sequence no. */
+void cfctrl_prune_req(struct cfctrl *ctrl)
+{
+	struct cfctrl_request_info *p;
+	struct cfctrl_request_info *del;
+
+	cfglu_lock(ctrl->info_list_lock);
+	if (ctrl->first_req == NULL) {
+		cfglu_unlock(ctrl->info_list_lock);
+		return;
+	}
+
+	if (ctrl->first_req->sequence_no <
+	    cfglu_atomic_read(ctrl->req_seq_no)) {
+		del = ctrl->first_req;
+		ctrl->first_req = ctrl->first_req->next;
+		cfglu_free(del);
+	}
+	p = ctrl->first_req;
+	while (p->next != NULL) {
+		if (p->next->sequence_no <
+		    cfglu_atomic_read(ctrl->rsp_seq_no)) {
+			del = p->next;
+			p = p->next;
+			cfglu_atomic_set(ctrl->rsp_seq_no,
+					 ctrl->first_req->sequence_no);
+			cfglu_free(del);
+		}
+		p = p->next;
+	}
+	cfglu_unlock(ctrl->info_list_lock);
+}
+
+
+void cfctrl_set_respfuncs(layer_t *layer, cfctrl_rsp_t *respfuncs)
+{
+	struct cfctrl *this = container_obj(layer);
+	this->res = *respfuncs;
+}
+
+void cfctrl_set_dnlayer(layer_t *this, layer_t *dn)
+{
+	this->dn = dn;
+}
+
+void cfctrl_set_uplayer(layer_t *this, layer_t *up)
+{
+	this->up = up;
+}
+
+
+static transmt_info init_info(struct cfctrl *cfctrl)
+{
+	transmt_info info;
+	info.hdr_len = 0;
+	info.prio = 0;
+	info.channel_id = cfctrl->serv.layer.id;
+	info.phid = cfctrl->serv.phid;
+	return info;
+}
+
+void cfctrl_enum_req(layer_t *layer, uint8 physlinkid)
+{
+	struct cfctrl *cfctrl = container_obj(layer);
+	transmt_info info = init_info(cfctrl);
+	int ret;
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	cfglu_assert(offsetof(struct cfctrl, serv.layer) == 0);
+	info.phid = physlinkid;
+	cfctrl->serv.phid = physlinkid;
+	cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM);
+	cfpkt_addbdy(pkt, physlinkid);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0) {
+		CFLOG_ERROR(("Could not transmit enum message\n"));
+		cfpkt_destroy(pkt);
+	}
+}
+
+
+void cfctrl_linkup_request(layer_t *layer, cfctrl_link_param_t *param,
+			   layer_t *user_layer)
+{
+
+	struct cfctrl *cfctrl = container_obj(layer);
+	uint32 tmp32;
+	uint16 tmp16;
+	uint8 tmp8;
+	int ret;
+	char utility_name[16];
+	struct cfctrl_request_info *req;
+	transmt_info info = init_info(cfctrl);
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	CFLOG_TRACE(("cfctrl: enter linkup_request\n"));
+
+	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
+	cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype);
+	cfpkt_addbdy(pkt, (param->priority << 3) + param->phyid);
+	cfpkt_addbdy(pkt, param->endpoint & 0x03);
+	CFLOG_TRACE2(("channel config: chtype:%d linktype:%d "
+		      "phyid:%d prio:%d endpoint:%d\n",
+		      param->chtype, param->linktype,
+		      param->phyid, param->priority, param->endpoint));
+
+	switch (param->linktype) {
+	case CFCTRL_SRV_VEI:
+		break;
+
+	case CFCTRL_SRV_VIDEO:
+		cfpkt_addbdy(pkt, (uint8) param->u.video.connid);
+		break;
+
+	case CFCTRL_SRV_DBG:
+		break;
+
+	case CFCTRL_SRV_DATAGRAM:
+		tmp32 = cfglu_cpu_to_le32(param->u.datagram.connid);
+		cfpkt_add_body(pkt, &tmp32, 4);
+		break;
+
+	case CFCTRL_SRV_RFM:
+		/* construct a frame Convert DatagramConnectionID to network
+		   format long and copy it out.. */
+		tmp32 = cfglu_cpu_to_le32(param->u.rfm.connid);
+		cfpkt_add_body(pkt, &tmp32, 4);
+		/* Add Volume name, including zero termination */
+		cfpkt_add_body(pkt, param->u.rfm.volume,
+			       strlen(param->u.rfm.volume) + 1);
+		break;
+
+	case CFCTRL_SRV_UTIL:
+		tmp16 = cfglu_cpu_to_le16(param->u.utility.fifosize_kb);
+		cfpkt_add_body(pkt, &tmp16, 2);
+		tmp16 = cfglu_cpu_to_le16(param->u.utility.fifosize_bufs);
+		cfpkt_add_body(pkt, &tmp16, 2);
+		memset(utility_name, 0, sizeof(utility_name));
+		strncpy(utility_name, param->u.utility.name,
+			UTILITY_NAME_LENGTH - 1);
+		cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH);
+		tmp8 = param->u.utility.paramlen;
+		cfpkt_add_body(pkt, &tmp8, 1);
+		cfpkt_add_body(pkt, param->u.utility.params,
+			       param->u.utility.paramlen);
+		CFLOG_TRACE2(("util config: kb:%d bufs:%d name:%s paramlen:%d"
+			      "param:0x%02x,%02x,%02x,%02x,%02x\n",
+			      param->u.utility.fifosize_kb,
+			      param->u.utility.fifosize_bufs,
+			      utility_name,
+			      param->u.utility.paramlen,
+			      param->u.utility.params[0],
+			      param->u.utility.params[1],
+			      param->u.utility.params[2],
+			      param->u.utility.params[3],
+			      param->u.utility.params[4]));
+		break;
+
+	default:
+		CFLOG_ERROR(("CAIF: Request setup of invalid link type = %d\n",
+			     param->linktype));
+	}
+	req = cfglu_alloc(sizeof(*req));
+	memset(req, 0, sizeof(*req));
+	req->client_layer = user_layer;
+	req->cmd = CFCTRL_CMD_LINK_SETUP;
+	req->param = *param;
+	cfctrl_insert_req(cfctrl, req);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0) {
+		CFLOG_ERROR(("cfctl: Could not transmit linksetup request\n"));
+		cfpkt_destroy(pkt);
+	}
+}
+
+void cfctrl_linkdown_req(layer_t *layer, uint8 channelid, layer_t *client)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	struct cfctrl_request_info *req = cfglu_alloc(sizeof(*req));
+	transmt_info info = init_info(cfctrl);
+	cfctrl_insert_req2(cfctrl, CFCTRL_CMD_LINK_DESTROY, channelid, client);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
+	cfpkt_addbdy(pkt, channelid);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0) {
+		CFLOG_ERROR(("cfctl: Could not transmit link-down request\n"));
+		cfpkt_destroy(pkt);
+	}
+}
+
+void cfctrl_sleep_req(layer_t *layer)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+
+}
+
+void cfctrl_wake_req(layer_t *layer)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+void cfctrl_getstartreason_req(layer_t *layer)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+
+void cfctrl_setmode_req(layer_t *layer, uint8 mode)
+{
+	int ret;
+	struct cfctrl *cfctrl = container_obj(layer);
+	cfpkt_t *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+	transmt_info info = init_info(cfctrl);
+	cfpkt_addbdy(pkt, CFCTRL_CMD_RADIO_SET);
+	cfpkt_addbdy(pkt, mode);
+	ret =
+	    cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_destroy(pkt);
+}
+
+
+
+static int cfctrl_recv(struct cfctrl *cfctrl, cfpkt_t *pkt)
+{
+	uint8 cmdrsp;
+	uint8 cmd;
+	int ret = -1;
+	uint16 tmp16;
+	uint8 len;
+	uint8 param[255];
+	uint8 linkid;
+	struct cfctrl_request_info rsp, *req;
+
+	CFLOG_TRACE(("cfctrl: enter cfctrl_recv\n"));
+
+	(void) cfpkt_extr_head(pkt, &cmdrsp, 1);
+	cmd = cmdrsp & CFCTRL_CMD_MASK;
+	if (cmd != CFCTRL_CMD_LINK_ERR
+	    && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) {
+		CFLOG_ERROR(("CAIF Protocol error: Response bit not set\n"));
+		goto error;
+	}
+
+	switch (cmd) {
+	case CFCTRL_CMD_LINK_SETUP:
+		{
+			cfctrl_srv_t serv;
+			cfctrl_srv_t servtype;
+			uint8 endpoint;
+			uint8 physlinkid;
+			uint8 prio;
+			uint8 tmp;
+			uint32 tmp32;
+			uint8 *cp;
+			int i;
+			cfctrl_link_param_t linkparam;
+			memset(&linkparam, 0, sizeof(linkparam));
+
+			cfpkt_extr_head(pkt, &tmp, 1);
+
+			serv = tmp & CFCTRL_SRV_MASK;
+			linkparam.linktype = serv;
+
+			servtype = tmp >> 4;
+			linkparam.chtype = servtype;
+
+			cfpkt_extr_head(pkt, &tmp, 1);
+			physlinkid = tmp & 0x07;
+			prio = tmp >> 3;
+
+			linkparam.priority = prio;
+			linkparam.phyid = physlinkid;
+			cfpkt_extr_head(pkt, &endpoint, 1);
+			linkparam.endpoint = endpoint & 0x03;
+
+			switch (serv) {
+			case CFCTRL_SRV_VEI:
+			case CFCTRL_SRV_DBG:
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				break;
+			case CFCTRL_SRV_VIDEO:
+				cfpkt_extr_head(pkt, &tmp, 1);
+				linkparam.u.video.connid = tmp;
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				break;
+
+			case CFCTRL_SRV_DATAGRAM:
+				cfpkt_extr_head(pkt, &tmp32, 4);
+				linkparam.u.datagram.connid =
+				    cfglu_le32_to_cpu(tmp32);
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+				break;
+
+			case CFCTRL_SRV_RFM:
+				/* construct a frame Conver
+				   DatagramConnectionID to network format long
+				   and copy it out.. */
+
+				cfpkt_extr_head(pkt, &tmp32, 4);
+				linkparam.u.rfm.connid =
+				  cfglu_le32_to_cpu(tmp32);
+				cp = (uint8 *) linkparam.u.rfm.volume;
+				for (cfpkt_extr_head(pkt, &tmp, 1);
+				     cfpkt_more(pkt) && tmp != '\0';
+				     cfpkt_extr_head(pkt, &tmp, 1))
+					*cp++ = tmp;
+				*cp = '\0';
+
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+
+				break;
+			case CFCTRL_SRV_UTIL:
+
+				/* construct a frame Conver
+				   DatagramConnectionID to network format long
+				   and copy it out.. */
+				/* Fifosize KB */
+				cfpkt_extr_head(pkt, &tmp16, 2);
+				linkparam.u.utility.fifosize_kb =
+				    cfglu_le16_to_cpu(tmp16);
+				/* Fifosize bufs */
+				cfpkt_extr_head(pkt, &tmp16, 2);
+				linkparam.u.utility.fifosize_bufs =
+				    cfglu_le16_to_cpu(tmp16);
+
+				/* name */
+				cp = (uint8 *) linkparam.u.utility.name;
+				cfglu_assert(sizeof(linkparam.u.utility.name)
+					     >= UTILITY_NAME_LENGTH);
+				for (i = 0;
+				     i < UTILITY_NAME_LENGTH
+				     && cfpkt_more(pkt); i++) {
+					cfpkt_extr_head(pkt, &tmp, 1);
+					*cp++ = tmp;
+				}
+				/* Length */
+				cfpkt_extr_head(pkt, &len, 1);
+				linkparam.u.utility.paramlen = len;
+				/* Param Data */
+				cp = linkparam.u.utility.params;
+				while (cfpkt_more(pkt) && len--) {
+					cfpkt_extr_head(pkt, &tmp, 1);
+					*cp++ = tmp;
+				}
+
+				/* Link ID */
+				cfpkt_extr_head(pkt, &linkid, 1);
+
+				/* Length */
+				cfpkt_extr_head(pkt, &len, 1);
+
+				/* Param Data */
+				cfpkt_extr_head(pkt, &param, len);
+
+				break;
+			default:
+				CFLOG_ERROR(("cfctrl_rec:Request setup "
+					     "- invalid link type (%d)",
+					     serv));
+				goto error;
+			}
+
+			if (cfpkt_erroneous(pkt)) {
+				CFLOG_ERROR(("cfctrl: Packet is erroneous!"));
+				goto error;
+			}
+			CFLOG_TRACE(("cfctrl: success parsing linksetup_rsp"));
+			rsp.cmd = cmd;
+			rsp.param = linkparam;
+			req = cfctrl_remove_req(cfctrl, &rsp);
+
+			if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp)) {
+				CFLOG_ERROR(("CaifChannel:Invalid O/E bit "
+					     "on CAIF control channel"));
+				cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
+						       0,
+						       req ? req->client_layer
+						       : NULL);
+			} else {
+				cfctrl->res.linksetup_rsp(cfctrl->serv.
+							  layer.up, linkid,
+							  serv, physlinkid,
+							  req ? req->
+							  client_layer : NULL);
+			}
+
+			if (req != NULL)
+				cfglu_free(req);
+		}
+		break;
+
+	case CFCTRL_CMD_LINK_DESTROY:
+		cfpkt_extr_head(pkt, &linkid, 1);
+		rsp.cmd = cmd;
+		rsp.channel_id = linkid;
+		req = cfctrl_remove_req(cfctrl, &rsp);
+		cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid,
+					    req ? req->client_layer : NULL);
+		if (req != NULL)
+			cfglu_free(req);
+		break;
+
+	case CFCTRL_CMD_LINK_ERR:
+		CFLOG_ERROR(("cfctrl: Frame Error Indication received \n"));
+		cfctrl->res.linkerror_ind();
+		break;
+
+	case CFCTRL_CMD_ENUM:
+		cfctrl->res.enum_rsp();
+		break;
+
+	case CFCTRL_CMD_SLEEP:
+		cfctrl->res.sleep_rsp();
+		break;
+
+	case CFCTRL_CMD_WAKE:
+		cfctrl->res.wake_rsp();
+		break;
+
+	case CFCTRL_CMD_LINK_RECONF:
+		cfctrl->res.restart_rsp();
+		break;
+
+	case CFCTRL_CMD_RADIO_SET:
+		cfctrl->res.radioset_rsp();
+		break;
+
+	default:
+		CFLOG_ERROR(("CAIF: Unrecognized Control Frame\n"));
+		goto error;
+		break;
+	}
+	ret = 0;
+error:
+	cfpkt_destroy(pkt);
+	return ret;
+}
+
+static void cfctrl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	struct cfctrl *this = container_obj(layr);
+	CFLOG_ENTER(("\n"));
+	switch (ctrl) {
+	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+		cfglu_lock(this->info_list_lock);
+		if (this->first_req != NULL) {
+			CFLOG_WARN(("cfctrl:"
+				    "Received flow off in control layer"));
+		}
+		cfglu_unlock(this->info_list_lock);
+		break;
+
+	default:
+		break;
+	}
+	CFLOG_EXIT(("\n"));
+}
diff --git a/net/caif/generic/cfdgml.c b/net/caif/generic/cfdgml.c
new file mode 100644
index 0000000..b499c2c
--- /dev/null
+++ b/net/caif/generic/cfdgml.c
@@ -0,0 +1,119 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+#define container_obj(layr) ((cfsrvl_t *) layr)
+
+#define DGM_CMD_BIT  0x80
+#define DGM_FLOW_OFF 0x81
+#define DGM_FLOW_ON  0x80
+#define DGM_CTRL_PKT_SIZE 1
+
+static int cfdgml_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfdgml_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt);
+
+layer_t *cfdgml_create(uint8 channel_id, uint8 phyid)
+{
+	cfsrvl_t *dgm = cfglu_alloc(sizeof(cfsrvl_t));
+	cfglu_assert(offsetof(cfsrvl_t, layer) == 0);
+	CFLOG_ENTER(("\n"));
+	memset(dgm, 0, sizeof(cfsrvl_t));
+	cfsrvl_init(dgm, channel_id, phyid);
+	dgm->layer.receive = cfdgml_receive;
+	dgm->layer.transmit = cfdgml_transmit;
+	sprintf(dgm->layer.name, "dgm%d", channel_id);
+	CFLOG_EXIT(("\n"));
+	return &dgm->layer;
+}
+
+static int cfdgml_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	uint8 cmd = -1;
+	uint8 dgmhdr[3];
+	int ret;
+	cfglu_assert(layr->up != NULL);
+	cfglu_assert(layr->receive != NULL);
+	cfglu_assert(layr->ctrlcmd != NULL);
+	CFLOG_ENTER(("\n"));
+
+	if (!cfpkt_extr_head(pkt, &cmd, 1)) {
+		CFLOG_ERROR(("cfdgml: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EPROTO;
+	}
+
+	if ((cmd & DGM_CMD_BIT) == 0) {
+		if (!cfpkt_extr_head(pkt, &dgmhdr, 3)) {
+			CFLOG_ERROR(("cfdgml: Packet is erroneous!\n"));
+			cfpkt_destroy(pkt);
+			return CFGLU_EPROTO;
+		}
+		ret = layr->up->receive(layr->up, pkt);
+		CFLOG_EXIT(("\n"));
+		return ret;
+	}
+
+	switch (cmd) {
+	case DGM_FLOW_OFF:	/* FLOW OFF */
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return 0;
+	case DGM_FLOW_ON:	/* FLOW ON */
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return 0;
+	default:
+		cfpkt_destroy(pkt);
+		CFLOG_ERROR(("cfdgml: Unknown datagram control %d (0x%x)\n",
+			     cmd, cmd));
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EPROTO;
+	}
+	CFLOG_EXIT(("\n"));
+}
+
+static int cfdgml_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt)
+{
+	uint32 zero = 0;
+	transmt_info info;
+	cfsrvl_t *service = container_obj(layr);
+	int ret;
+	CFLOG_ENTER(("\n"));
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	cfpkt_add_head(pkt, &zero, 4);
+
+	/* Add info for MUX-layer to route the packet out */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	/* For optimizing alignment we add up the size of CAIF header before
+	   payload */
+	info.hdr_len = 4;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0) {
+		uint32 tmp32;
+		cfpkt_extr_head(pkt, &tmp32, 4);
+	}
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
diff --git a/net/caif/generic/cffrml.c b/net/caif/generic/cffrml.c
new file mode 100644
index 0000000..243cf41
--- /dev/null
+++ b/net/caif/generic/cffrml.c
@@ -0,0 +1,146 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ *      Caif Framing Layer.
+ */
+
+#define container_obj(layr) cfglu_container_of(layr, cffrml_t, layer)
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+#include <net/caif/generic/cffrml.h>
+
+struct _cffrml_t {
+	layer_t layer;
+	bool dofcs;		/* !< FCS active */
+};
+
+
+static int cffrml_receive(layer_t *layr, cfpkt_t *pkt);
+static int cffrml_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt);
+static void cffrml_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid);
+
+uint32 cffrml_rcv_error;
+uint32 cffrml_rcv_checsum_error;
+layer_t *cffrml_create(uint16 phyid, bool use_fcs)
+{
+	cffrml_t *this = cfglu_alloc(sizeof(cffrml_t));
+	cfglu_assert(offsetof(cffrml_t, layer) == 0);
+
+	memset(this, 0, sizeof(layer_t));
+	this->layer.receive = cffrml_receive;
+	this->layer.transmit = cffrml_transmit;
+	this->layer.ctrlcmd = cffrml_ctrlcmd;
+	sprintf(this->layer.name, "frm%d", phyid);
+	this->dofcs = use_fcs;
+	this->layer.id = phyid;
+	CFLOG_TRACE(("cffrml: FCS=%d\n", use_fcs));
+	return (layer_t *) this;
+}
+
+void cffrml_set_uplayer(layer_t *this, layer_t *up)
+{
+	this->up = up;
+}
+
+void cffrml_set_dnlayer(layer_t *this, layer_t *dn)
+{
+	this->dn = dn;
+}
+
+static uint16 cffrml_checksum(uint16 chks, void *buf, uint16 len)
+{
+	/* FIXME: FCS should be moved to glue in order to use OS-Specific
+	   solutions */
+	return fcs16(chks, buf, len);
+}
+
+static int cffrml_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	uint16 tmp;
+	uint16 len;
+	uint16 hdrchks;
+	uint16 pktchks;
+	cffrml_t *this;
+	this = container_obj(layr);
+
+
+	(void) cfpkt_extr_head(pkt, &tmp, 2);
+	len = cfglu_le16_to_cpu(tmp);
+
+	/* Subtract for FCS on length if FCS is not used. */
+	if (!this->dofcs)
+		len -= 2;
+
+	if (cfpkt_setlen(pkt, len) < 0) {
+		++cffrml_rcv_error;
+		CFLOG_ERROR(("cffrml: Framing length error (%d)\n", len));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPKT;
+	}
+	/* Don't do extract if fcs is false, rather to setlen - then we don'
+	   get cach-miss */
+	if (this->dofcs) {
+		(void) cfpkt_extr_trail(pkt, &tmp, 2);
+		hdrchks = cfglu_le16_to_cpu(tmp);
+		pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
+		if (pktchks != hdrchks) {
+			cfpkt_add_trail(pkt, &tmp, 2);
+			++cffrml_rcv_error;
+			++cffrml_rcv_checsum_error;
+			CFLOG_ERROR(("cffrml: Frame checksum error "
+				     "(0x%x != 0x%x)\n", hdrchks, pktchks));
+			return CFGLU_EFCS;
+		}
+	}
+	if (cfpkt_erroneous(pkt)) {
+		++cffrml_rcv_error;
+		CFLOG_ERROR(("cffrml: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPKT;
+	}
+	return layr->up->receive(layr->up, pkt);
+}
+
+static int cffrml_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	int tmp;
+	uint16 chks;
+	uint16 len;
+	int ret;
+	cffrml_t *this = container_obj(layr);
+	if (this->dofcs) {
+		chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
+		tmp = cfglu_cpu_to_le16(chks);
+		cfpkt_add_trail(pkt, &tmp, 2);
+	} else {
+		cfpkt_pad_trail(pkt, 2);
+	}
+
+	len = cfpkt_getlen(pkt);
+	tmp = cfglu_cpu_to_le16(len);
+	cfpkt_add_head(pkt, &tmp, 2);
+	info->hdr_len += 2;
+	if (cfpkt_erroneous(pkt)) {
+		CFLOG_ERROR(("cffrml: Packet is erroneous!\n"));
+		return CFGLU_EPROTO;
+	}
+	ret = layr->dn->transmit(layr->dn, info, pkt);
+	if (ret < 0) {
+		/* Remove header on faulty packet */
+		cfpkt_extr_head(pkt, &tmp, 2);
+	}
+	return ret;
+}
+
+static void cffrml_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	if (layr->up->ctrlcmd)
+		layr->up->ctrlcmd(layr->up, ctrl, layr->id);
+}
diff --git a/net/caif/generic/cflist.c b/net/caif/generic/cflist.c
new file mode 100644
index 0000000..7b0b8d2
--- /dev/null
+++ b/net/caif/generic/cflist.c
@@ -0,0 +1,99 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+
+void cflst_init(layer_t **lst)
+{
+	*lst = NULL;
+}
+
+
+layer_t *cflst_remove(layer_t **lst, layer_t *elem)
+{
+	layer_t *tmp;
+	if (*lst == NULL)
+		return NULL;
+
+	tmp = (*lst);
+	(*lst) = (*lst)->next;
+	return tmp;
+}
+
+/** Adds an element from the Queue */
+
+void cflst_insert(layer_t **lst, layer_t *node)
+{
+	layer_t *tmp;
+	node->next = NULL;
+	if ((*lst) == NULL) {
+		(*lst) = node;
+		return;
+	}
+	tmp = *lst;
+	while (tmp->next != NULL)
+		tmp = tmp->next;
+	tmp->next = node;
+}
+
+
+
+bool cflst_put(layer_t **lst, uint8 id, layer_t *node)
+{
+	if (cflst_get(lst, id) != NULL) {
+		CFLOG_ERROR(("CAIF: cflst_put duplicate key\n"));
+		return false;
+	}
+	node->id = id;
+	cflst_insert(lst, node);
+	return true;
+}
+
+layer_t *cflst_get(layer_t * *lst, uint8 id)
+{
+	layer_t *node;
+	for (node = (*lst); node != NULL; node = node->next) {
+		if (id == node->id)
+			return node;
+	}
+	return NULL;
+}
+
+layer_t *cflst_del(layer_t * *lst, uint8 id)
+{
+	layer_t *iter;
+	layer_t *node = NULL;
+
+	if ((*lst) == NULL)
+		return NULL;
+
+	if ((*lst)->id == id) {
+		node = (*lst);
+		(*lst) = (*lst)->next;
+		node->next = NULL;
+
+		return node;
+	}
+
+	for (iter = (*lst); iter->next != NULL; iter = iter->next) {
+		if (id == iter->next->id) {
+			node = iter->next;
+			iter->next = iter->next->next;
+			node->next = NULL;
+			return node;
+		}
+	}
+	return NULL;
+}
diff --git a/net/caif/generic/cfloopcfg.c b/net/caif/generic/cfloopcfg.c
new file mode 100644
index 0000000..b7b7f1b
--- /dev/null
+++ b/net/caif/generic/cfloopcfg.c
@@ -0,0 +1,93 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfmuxl.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/generic/cfspil.h>
+#include <net/caif/generic/cfserl.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfshml.h>
+#include <net/caif/generic/cfmsll.h>
+struct _cfloopcfg_t {
+	layer_t *loop;
+
+};
+typedef struct _cfloopcfg_t cfloopcfg_t;
+
+cfloopcfg_t *cfloopcfg_create(void)
+{
+	extern layer_t *cflooplayer_create(void);
+	cfloopcfg_t *this;
+	this = cfglu_alloc(sizeof(cfloopcfg_t));
+	memset(this, 0, sizeof(cfloopcfg_t));
+	this->loop = cflooplayer_create();
+	return this;
+}
+
+void
+cfloopcfg_add_phy_layer(cfloopcfg_t *cnfg, cfcnfg_phy_type_t phy_type,
+			layer_t *phy_layer)
+{
+	if (phy_type == CFPHYTYPE_SERIAL) {
+		layer_t *frml = cffrml_create(1, true);
+		layer_t *cfser;
+		cfser = cfserl_create(phy_type, 0, serial_use_stx);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfser);
+		layer_set_up(cfser, frml);
+		layer_set_dn(cfser, phy_layer);
+		layer_set_up(phy_layer, cfser);
+	}
+	if (phy_type == CFPHYTYPE_SPI) {
+		layer_t *frml = cffrml_create(1, false);
+		layer_t *cfspi;
+		cfspi = cfspil_create(phy_type, 0);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfspi);
+		layer_set_up(cfspi, frml);
+		layer_set_dn(cfspi, phy_layer);
+		layer_set_up(phy_layer, cfspi);
+	}
+	if (phy_type == CFPHYTYPE_SHM) {
+		layer_t *frml = cffrml_create(1, false);
+		layer_t *cfspi;
+		cfspi = cfshml_create(phy_type, 0);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfspi);
+		layer_set_up(cfspi, frml);
+		layer_set_dn(cfspi, phy_layer);
+		layer_set_up(phy_layer, cfspi);
+	}
+	if (phy_type == CFPHYTYPE_MSL) {
+		layer_t *frml = cffrml_create(1, false);
+		layer_t *cfspi;
+		cfspi = cfmsll_create(phy_type, 0);
+		layer_set_dn(cnfg->loop, frml);
+		layer_set_up(frml, cnfg->loop);
+		layer_set_dn(frml, cfspi);
+		layer_set_up(cfspi, frml);
+		layer_set_dn(cfspi, phy_layer);
+		layer_set_up(phy_layer, cfspi);
+	}
+}
diff --git a/net/caif/generic/cflooplayer.c b/net/caif/generic/cflooplayer.c
new file mode 100644
index 0000000..ef731ca
--- /dev/null
+++ b/net/caif/generic/cflooplayer.c
@@ -0,0 +1,116 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/generic/cfctrl.h>
+
+static int cflooplayer_receive(layer_t *layr, cfpkt_t *pkt);
+static uint8 linkid;
+static int linkused[256];
+static cfglu_lock_t linkid_lock;
+
+layer_t *cflooplayer_create(void)
+{
+	layer_t *this = cfglu_alloc(sizeof(layer_t));
+	memset(this, 0, sizeof(layer_t));
+	this->receive = cflooplayer_receive;
+	cfglu_init_lock(linkid_lock);
+	sprintf(this->name, "loop1");
+	return this;
+}
+
+
+static int cflooplayer_receive(layer_t *layr, cfpkt_t *inpkt)
+{
+	uint8 id;
+	transmt_info info;
+	uint8 *buf;
+	uint16 pktlen;
+	cfpkt_t *pkt;
+	int ret;
+	caif_packet_funcs_t f = cfpkt_get_packet_funcs();
+	memset(&info, 0, sizeof(info));
+	pktlen = cfpkt_getlen(inpkt);
+	ret = f.cfpkt_raw_extract(inpkt, (void **) &buf, pktlen);
+	cfglu_assert(ret > 0);
+	pkt = f.cfpkt_create_recv_pkt(buf, pktlen);
+	cfpkt_destroy(inpkt);
+	(void) cfpkt_extr_head(pkt, &id, 1);
+	if (id != 0) {
+		/* This is not a Control Packet, just loop it */
+		cfpkt_add_head(pkt, &id, 1);
+	} else {
+		/* This is a Control Packet */
+		uint8 tmp;
+		uint8 cmdrsp;
+		uint8 cmd;
+		uint8 linktype = 0;
+
+		(void) cfpkt_extr_head(pkt, &cmdrsp, 1);
+		cmd = cmdrsp & CFCTRL_CMD_MASK;
+
+		switch (cmd) {
+		case CFCTRL_CMD_LINK_SETUP:
+			{
+				cfglu_assert(!cfpkt_erroneous(pkt));
+				cfglu_assert(cfpkt_more(pkt));
+				cfpkt_peek_head(pkt, &linktype, 1);
+				cfglu_assert(!cfpkt_erroneous(pkt));
+				cmdrsp |= CFCTRL_RSP_BIT;
+				cfpkt_add_head(pkt, &cmdrsp, 1);
+				cfpkt_add_head(pkt, &id, 1);
+				cfglu_lock(linkid_lock);
+				for (linkid = 0x41; linkid < 255; linkid++) {
+					if (!linkused[linkid]) {
+						linkused[linkid] = 1;
+						break;
+					}
+				}
+				if (linkid == 255) {
+					CFLOG_WARN(("cflooplayer_receive:"
+						    " no free link id's\n"));
+				}
+				CFLOG_WARN(("cflooplayer_receive: setup "
+					    "linkid = %d\n", linkid));
+				cfpkt_add_trail(pkt, &linkid, 1);
+				cfglu_unlock(linkid_lock);
+
+
+
+				if (linktype == 0x06) {
+					tmp = 0x01;
+					cfpkt_add_trail(pkt, &tmp, 1);
+					cfpkt_add_trail(pkt, &tmp, 1);
+				}
+				break;
+			}
+		case CFCTRL_CMD_LINK_DESTROY:
+			cfglu_lock(linkid_lock);
+			(void) cfpkt_peek_head(pkt, &linkid, 1);
+			CFLOG_WARN(("cflooplayer_receive: destroy "
+				    "linkid = %d\n", linkid));
+			linkused[linkid] = 0;
+			cfglu_unlock(linkid_lock);
+			/* fallthrough */
+		default:
+			cmdrsp |= CFCTRL_RSP_BIT;
+			cfpkt_add_head(pkt, &cmdrsp, 1);
+			cfpkt_add_head(pkt, &id, 1);
+			break;
+		}
+	}
+	return layr->dn->transmit(layr->dn, &info, pkt);
+}
diff --git a/net/caif/generic/cfmsll.c b/net/caif/generic/cfmsll.c
new file mode 100644
index 0000000..b01745e
--- /dev/null
+++ b/net/caif/generic/cfmsll.c
@@ -0,0 +1,55 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfmsll.h>
+
+static int cfmsll_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfmsll_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt);
+
+layer_t *cfmsll_create(int type, int instance)
+{
+	layer_t *this = cfglu_alloc(sizeof(layer_t));
+	memset(this, 0, sizeof(layer_t));
+	this->receive = cfmsll_receive;
+	this->transmit = cfmsll_transmit;
+	this->type = type;
+	sprintf(this->name, "msl%d", instance);
+	return this;
+}
+
+void cfmsll_set_uplayer(layer_t *this, layer_t *up)
+{
+	this->up = up;
+}
+
+void cfmsll_set_dnlayer(layer_t *this, layer_t *dn)
+{
+	this->dn = dn;
+
+}
+
+static int cfmsll_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	/* Send the first part of packet upwards */
+	int ret = layr->up->receive(layr->up, pkt);
+	/* FCS Error don't delete the packet */
+	if (ret == CFGLU_EFCS)
+		cfpkt_destroy(pkt);
+	return ret;
+
+}
+
+static int cfmsll_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	return layr->dn->transmit(layr->dn, info, pkt);
+}
diff --git a/net/caif/generic/cfmuxl.c b/net/caif/generic/cfmuxl.c
new file mode 100644
index 0000000..9dbc6c7
--- /dev/null
+++ b/net/caif/generic/cfmuxl.c
@@ -0,0 +1,258 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cflst.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfmuxl.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cffrml.h>
+
+#define container_obj(layr) cfglu_container_of(layr, struct cfmuxl_t, layer)
+
+
+#define CAIF_CTRL_CHANNEL 0
+#define UP_CACHE_SIZE 8
+#define DN_CACHE_SIZE 8
+
+
+struct cfmuxl_t {
+	layer_t layer;
+	layer_t *up_cache[UP_CACHE_SIZE];
+	layer_t *dn_cache[DN_CACHE_SIZE];
+	/*
+	 * transmit_lock is a read-write lock.
+	 * writelock is set when inserting or removing down layers.
+	 */
+	cfglu_rwlock_t transmit_lock;
+
+	/*
+	 * receive_lock is a read-write lock.
+	 * writelock is set when inserting or removing up-wards layers.
+	 */
+	cfglu_rwlock_t receive_lock;
+
+};
+
+static int cfmuxl_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfmuxl_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt);
+static void cfmuxl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid);
+static layer_t *get_up(struct cfmuxl_t *muxl, int id);
+
+layer_t *cfmuxl_create()
+{
+	struct cfmuxl_t *this = cfglu_alloc(sizeof(struct cfmuxl_t));
+	memset(this, 0, sizeof(*this));
+	this->layer.receive = cfmuxl_receive;
+	this->layer.transmit = cfmuxl_transmit;
+	this->layer.ctrlcmd = cfmuxl_ctrlcmd;
+	cfglu_init_rwlock(this->transmit_lock);
+	cfglu_init_rwlock(this->receive_lock);
+	sprintf(this->layer.name, "mux");
+	return &this->layer;
+}
+
+bool cfmuxl_set_uplayer(layer_t *layr, layer_t *up, uint8 linkid)
+{
+	bool ok;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	CFLOG_ENTER(("layr:%p up:%p linkid:%d\n", (void *) layr, (void *) up,
+		     linkid));
+	cfglu_write_lock(muxl->receive_lock);
+	ok = cflst_put(&muxl->layer.up, linkid, up);
+	cfglu_write_unlock(muxl->receive_lock);
+	CFLOG_EXIT(("ok=%d\n", ok));
+	return ok;
+}
+
+bool cfmuxl_is_phy_inuse(layer_t *layr, uint8 phyid)
+{
+	layer_t *p;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	bool match = false;
+	cfglu_read_lock(muxl->receive_lock);
+	CFLOG_ENTER(("\n"));
+
+	for (p = layr->up; p != NULL; p = p->next) {
+		if (cfsrvl_phyid_match(p, phyid)) {
+			match = true;
+			break;
+		}
+	}
+	cfglu_read_unlock(muxl->receive_lock);
+	CFLOG_EXIT(("\n"));
+	return match;
+}
+
+uint8 cfmuxl_get_phyid(layer_t *layr, uint8 channel_id)
+{
+	layer_t *up;
+	int phyid;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	cfglu_read_lock(muxl->receive_lock);
+	CFLOG_ENTER(("\n"));
+	up = get_up(muxl, channel_id);
+	if (up != NULL)
+		phyid = cfsrvl_getphyid(up);
+	else
+		phyid = 0;
+	cfglu_read_unlock(muxl->receive_lock);
+	return phyid;
+}
+
+bool cfmuxl_set_dnlayer(layer_t *layr, layer_t *dn, uint8 phyid)
+{
+	bool ok;
+	struct cfmuxl_t *muxl = (struct cfmuxl_t *) layr;
+	CFLOG_ENTER(("\n"));
+	cfglu_write_lock(muxl->transmit_lock);
+	ok = cflst_put(&muxl->layer.dn, phyid, dn);
+	cfglu_write_unlock(muxl->transmit_lock);
+	CFLOG_EXIT(("\n"));
+	return ok;
+}
+
+layer_t *cfmuxl_remove_dnlayer(layer_t *layr, uint8 phyid)
+{
+	struct cfmuxl_t *muxl = container_obj(layr);
+	layer_t *dn;
+	CFLOG_ENTER(("\n"));
+	cfglu_write_lock(muxl->transmit_lock);
+	memset(muxl->dn_cache, 0, sizeof(muxl->dn_cache));
+	dn = cflst_del(&muxl->layer.dn, phyid);
+	cfglu_assert(dn != NULL);
+	cfglu_write_unlock(muxl->transmit_lock);
+	CFLOG_EXIT(("\n"));
+	return dn;
+}
+
+
+/* Invariant: lock is taken */
+static layer_t *get_up(struct cfmuxl_t *muxl, int id)
+{
+	layer_t *up;
+	int idx = id % UP_CACHE_SIZE;
+	CFLOG_ENTER(("id:%d\n", id));
+	up = muxl->up_cache[idx];
+	if (up == NULL || up->id != id) {
+		up = cflst_get(&muxl->layer.up, id);
+		muxl->up_cache[idx] = up;
+	}
+	CFLOG_EXIT(("id: %d up:%p", id, (void *) up));
+	return up;
+
+}
+
+/* Invariant: lock is taken */
+static layer_t *get_dn(struct cfmuxl_t *muxl, int id)
+{
+	layer_t *dn;
+	int idx = id % DN_CACHE_SIZE;
+	CFLOG_ENTER(("\n"));
+	dn = muxl->dn_cache[idx];
+	if (dn == NULL || dn->id != id) {
+		dn = cflst_get(&muxl->layer.dn, id);
+		muxl->dn_cache[idx] = dn;
+	}
+	CFLOG_EXIT(("\n"));
+	return dn;
+}
+
+
+
+
+
+layer_t *cfmuxl_remove_uplayer(layer_t *layr, uint8 id)
+{
+	layer_t *up;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	CFLOG_ENTER(("\n"));
+	cfglu_write_lock(muxl->receive_lock);
+	memset(muxl->up_cache, 0, sizeof(muxl->up_cache));
+	up = cflst_del(&muxl->layer.up, id);
+	cfglu_assert(up != NULL);
+	cfglu_write_unlock(muxl->receive_lock);
+	CFLOG_EXIT(("\n"));
+	return up;
+}
+
+
+static int cfmuxl_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	int ret;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	uint8 id;
+	layer_t *up;
+	CFLOG_ENTER(("\n"));
+	if (!cfpkt_extr_head(pkt, &id, 1)) {
+		CFLOG_ERROR(("cfmuxl: erroneous Caif Packet\n"));
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("error"));
+		return CFGLU_EPKT;
+	}
+
+	up = get_up(muxl, id);
+	if (up == NULL) {
+		CFLOG_WARN(("CAIF: Received data on unknown link ID = %d "
+			    "(0x%x)  up == NULL", id, id));
+		cfpkt_destroy(pkt);
+		/* Don't return ERROR since modem miss-behaves and sends ou
+		   flow before linksetup rsp. */
+		CFLOG_EXIT(("error - unknown channel"));
+		return /* CFGLU_EPROT; */ CFGLU_EOK;
+	}
+
+
+
+	ret = up->receive(up, pkt);
+
+	CFLOG_EXIT(("\n"));
+
+	return ret;
+}
+
+static int cfmuxl_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	int ret;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	uint8 linkid;
+	layer_t *dn;
+	CFLOG_ENTER(("\n"));
+
+	dn = get_dn(muxl, info->phid);
+	if (dn == NULL) {
+		CFLOG_WARN(("CAIF: Send data on unknown phy ID = %d (0x%x)\n",
+			    info->phid, info->phid));
+		CFLOG_EXIT(("error"));
+		return CFGLU_ENOTCONN;
+	}
+	info->hdr_len += 1;
+	linkid = info->channel_id;
+	cfpkt_add_head(pkt, &linkid, 1);
+
+	ret = dn->transmit(dn, info, pkt);
+	if (ret < 0) {
+		/** Remove MUX protocol header upon error */
+		cfpkt_extr_head(pkt, &linkid, 1);
+	}
+
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
+
+static void cfmuxl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	layer_t *p;
+	struct cfmuxl_t *muxl = container_obj(layr);
+	for (p = muxl->layer.up; p != NULL; p = p->next) {
+		if (cfsrvl_phyid_match(p, phyid))
+			p->ctrlcmd(p, ctrl, phyid);
+	}
+}
diff --git a/net/caif/generic/cfpkt_plain.c b/net/caif/generic/cfpkt_plain.c
new file mode 100644
index 0000000..2721990
--- /dev/null
+++ b/net/caif/generic/cfpkt_plain.c
@@ -0,0 +1,557 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+
+/* NOTE: Excluding physical layer max is 10 bytes, physical layer is
+   uncertain. */
+#define PKT_PREFIX 16
+#define PKT_POSTFIX 2
+
+/* Minimum size of payload buffer */
+#define PKT_MINSIZE 128
+
+#define CHECK_MEM 1
+#define MAGIC_VALUE 0xbaadf00d
+/* Return closest 32bit aligned address (by adding) */
+#define ALIGN32(p) (((((uint32)p)&0x3) == 0) ?\
+		    ((uint32) p) :\
+		    (((uint32)p) + (0x4 - (((uint32)p)&0x3))))
+
+/* Do division of 0 on failure - CRASH */
+#if CHECK_MEM
+#define CHECK_MAGIC(pkt) \
+	cfglu_assert(((pkt) != NULL && \
+			((pkt)->magic1 == MAGIC_VALUE && \
+					*(pkt)->magic2 == MAGIC_VALUE)))
+#endif
+
+
+
+/*
+ * Memory Layout:
+ * Magic1
+ * |   Buffer starts at start of page
+ * |   |		  Pad until next 32bit aligned offse
+ * |   |		  |   Magic2
+ * |   |		  |   |	  Packet Struct starts on first 32bit
+ * |   |		  |   |	  | aligned offset after end of packe
+ * V   V		  V   V	  V
+ * +---+-----------------+---+---+-----------------+
+ * |M2 | packet buffer ..|pad|M1 | struct _cfpkt_t |
+ * +---+-----------------+---+---+-----------------+
+ *     ^		 ^
+ *     |		 |
+ *     |		cfpkt._end_
+ *     cfpkt._head_
+ */
+
+struct _payload {
+#if CHECK_MEM
+	uint32 magic2;
+#endif
+	uint8 buf[1];
+};
+struct _cfpkt_t {
+#if CHECK_MEM
+	uint32 magic1;
+	uint32 *magic2;		/* This will point to location before _head_ */
+	void *blob;
+	struct _cfpkt_t *next;
+#endif
+	const uint8 *_head_;	/* Start of buffer, i.e. first legal pos for
+				   _data_ */
+	uint8 *_data_;		/* Start of payload */
+	uint8 *_tail_;		/* End of payload data */
+	uint8 *_end_;		/* End of buffer, i.e. last legal pos for
+				   _tail: */
+#if CHECK_MEM
+
+#endif
+};
+
+#define PKT_ERROR(pkt, errmsg) do {\
+	   pkt->_data_ = pkt->_tail_ = pkt->_end_ = (uint8 *)pkt->_head_;\
+	   CFLOG_ERROR((errmsg)); } while (0)
+
+
+struct _cfpktq_t {
+	cfpkt_t *head;
+	cfglu_lock_t qlock;
+};
+
+
+
+cfglu_atomic_t cfpkt_packet_count;
+
+cfpkt_t *cfpkt_create_pfx(uint16 len, uint16 pfx)
+{
+	int pldlen;
+	int bloblen;
+	cfpkt_t *pkt;
+	void *blob;
+	struct _payload *pld;
+	uint8 *pktstruct;
+	void *blobend, *structend;
+	cfglu_atomic_inc(cfpkt_packet_count);
+
+	/* (1) Compute payload length */
+	pldlen = len + pfx;
+	if (pldlen < PKT_MINSIZE)
+		pldlen = PKT_MINSIZE;
+#if CHECK_MEM
+	/* Make room for Magic before & after payload */
+	pldlen += 2 * sizeof(uint32);
+#endif
+	pldlen = ALIGN32(pldlen);
+
+	/* (2) Compute blob length, payload + packet struct */
+	bloblen = sizeof(struct _payload) + pldlen + sizeof(struct _cfpkt_t);
+
+	bloblen = ALIGN32(bloblen);
+
+	/* (3) Allocate the blob */
+	blob = cfglu_alloc(bloblen);
+
+	blobend = (uint8 *) blob + bloblen;
+
+	/* Initialize payload struct */
+	pld = (struct _payload *) blob;
+	pld->magic2 = MAGIC_VALUE;
+
+	/* Initialize packet struct */
+	pktstruct = pld->buf + pldlen;
+	pktstruct = (uint8 *) ALIGN32(pktstruct);
+	structend = pktstruct + sizeof(struct _cfpkt_t);
+	memset(pktstruct, 0, sizeof(struct _cfpkt_t));
+	cfglu_assert(structend <= blobend);
+	pkt = (struct _cfpkt_t *) pktstruct;
+	pkt->blob = blob;
+	pkt->_end_ = &pld->buf[pldlen];
+	pkt->_head_ = &pld->buf[0];
+	pkt->_data_ = (uint8 *) pkt->_head_ + pfx;
+	pkt->_tail_ = pkt->_data_;
+
+#if CHECK_MEM
+	pkt->magic1 = MAGIC_VALUE;
+	pkt->magic2 = (uint32 *) &pld->buf[pldlen];
+	*pkt->magic2 = MAGIC_VALUE;
+	CHECK_MAGIC(pkt);
+#endif
+	return pkt;
+}
+
+cfpkt_t *cfpkt_create(uint16 len)
+{
+	return cfpkt_create_pfx(len, PKT_PREFIX);
+}
+
+void cfpkt_destroy(cfpkt_t *pkt)
+{
+	CHECK_MAGIC(pkt);
+	cfglu_atomic_dec(cfpkt_packet_count);
+	cfglu_assert(cfglu_atomic_read(cfpkt_packet_count) >= 0);
+#if !CHECK_MEM
+	cfglu_free(pkt->_head_);
+#else
+	cfglu_free(pkt->blob);
+#endif
+}
+
+bool cfpkt_more(cfpkt_t *pkt)
+{
+	CHECK_MAGIC(pkt);
+	return pkt->_data_ < pkt->_tail_;
+}
+
+bool cfpkt_extr_head(cfpkt_t *pkt, void *dta, uint16 len)
+{
+	register int i;
+	uint8 *data = dta;
+	cfglu_assert(data != NULL);
+	CHECK_MAGIC(pkt);
+	CFLOG_TRACE3(("cfpkt_extr_head(%p,%p,%d)", (void *) pkt,
+		      (void *) dta, len));
+
+
+	if (pkt->_data_ + len > pkt->_tail_) {
+		PKT_ERROR(pkt,
+			  "cfpkt_extr_head would read beyond end of packet");
+		return false;
+	}
+	for (i = 0; i < len; i++) {
+		data[i] = *pkt->_data_;
+		pkt->_data_++;
+	}
+	CHECK_MAGIC(pkt);
+	return true;
+}
+
+bool cfpkt_extr_trail(cfpkt_t *pkt, void *dta, uint16 len)
+{
+	int i;
+	uint8 *data = dta;
+	cfglu_assert(data != NULL);
+	CHECK_MAGIC(pkt);
+	if (pkt->_data_ + len > pkt->_tail_) {
+		PKT_ERROR(pkt,
+			  "cfpkt_extr_trail would read beyond start of packet");
+		return false;
+	}
+	data += len;
+	for (i = 0; i < len; i++) {
+		data--;
+		pkt->_tail_--;
+		*data = *pkt->_tail_;
+	}
+	CHECK_MAGIC(pkt);
+	return true;
+}
+
+char *cfpkt_log_pkt(cfpkt_t *pkt, char *buf, int buflen)
+{
+	char *p = buf;
+	int i;
+	sprintf(buf, " pkt:%p len:%d {%d,%d} data: [",
+		(void *) pkt,
+		pkt->_tail_ - pkt->_data_,
+		pkt->_data_ - pkt->_head_, pkt->_tail_ - pkt->_head_);
+	p = buf + strlen(buf);
+
+	for (i = 0; i < pkt->_tail_ - pkt->_data_; i++) {
+		if (p > buf + buflen - 10) {
+			sprintf(p, "...");
+			p = buf + strlen(buf);
+			break;
+		}
+		sprintf(p, "%02x,", pkt->_data_[i]);
+		p = buf + strlen(buf);
+	}
+	sprintf(p, "]");
+	return buf;
+}
+
+bool cfpkt_add_body(cfpkt_t *pkt, const void *dta, uint16 len)
+{
+	register int i;
+	const uint8 *data = dta;
+	cfglu_assert(data != NULL);
+	CHECK_MAGIC(pkt);
+	if (pkt->_tail_ + len > pkt->_end_) {
+		PKT_ERROR(pkt,
+			  "cfpkt_add_body would write beyond end of packet");
+		return false;
+	}
+
+	for (i = 0; i < len; i++) {
+		*pkt->_tail_ = data[i];
+		pkt->_tail_++;
+	}
+	CHECK_MAGIC(pkt);
+	return true;
+}
+
+bool cfpkt_addbdy(cfpkt_t *pkt, uint8 data)
+{
+	CHECK_MAGIC(pkt);
+	return cfpkt_add_body(pkt, &data, 1);
+}
+
+bool cfpkt_add_head(cfpkt_t *pkt, const void *dta, uint16 len)
+{
+	register int i;
+	const uint8 *data = dta;
+	cfglu_assert(data != NULL);
+	CHECK_MAGIC(pkt);
+	if (pkt->_data_ - len < pkt->_head_) {
+		PKT_ERROR(pkt, "cfpkt_add_head: write beyond start of packet");
+		return false;
+	}
+	for (i = len - 1; i >= 0; i--) {
+		--pkt->_data_;
+		*pkt->_data_ = data[i];
+	}
+	CHECK_MAGIC(pkt);
+	return true;
+}
+
+bool cfpkt_add_trail(cfpkt_t *pkt, const void *data, uint16 len)
+{
+	CHECK_MAGIC(pkt);
+	cfglu_assert(data != NULL);
+	return cfpkt_add_body(pkt, data, len);
+
+}
+
+uint16 cfpkt_iterate(cfpkt_t *pkt, iterfunc_t func, uint16 data)
+{
+	return func(data, pkt->_data_, cfpkt_getlen(pkt));
+}
+
+int cfpkt_setlen(cfpkt_t *pkt, uint16 len)
+{
+	CHECK_MAGIC(pkt);
+	if (pkt->_data_ + len > pkt->_end_) {
+		PKT_ERROR(pkt, "cfpkt_setlen: Erroneous packet");
+		return 0;
+	}
+	pkt->_tail_ = pkt->_data_ + len;
+	return cfpkt_getlen(pkt);
+}
+
+uint16 cfpkt_getlen(cfpkt_t *pkt)
+{
+	CHECK_MAGIC(pkt);
+	return pkt->_tail_ - pkt->_data_;
+}
+
+void cfpkt_extract(cfpkt_t *cfpkt, void *buf, unsigned int buflen,
+		   unsigned int *actual_len)
+{
+	uint16 pklen = cfpkt_getlen(cfpkt);
+	cfglu_assert(buf != NULL);
+	cfglu_assert(actual_len != NULL);
+	CHECK_MAGIC(cfpkt);
+	if (buflen < pklen)
+		pklen = buflen;
+	*actual_len = pklen;
+	cfpkt_extr_head(cfpkt, buf, pklen);
+	CHECK_MAGIC(cfpkt);
+}
+
+cfpkt_t *cfpkt_create_uplink(const unsigned char *data, unsigned int len)
+{
+	cfpkt_t *pkt = cfpkt_create_pfx(len, PKT_PREFIX);
+	if (data != NULL)
+		cfpkt_add_body(pkt, data, len);
+	CHECK_MAGIC(pkt);
+	return pkt;
+}
+
+cfpkt_t *cfpkt_append(cfpkt_t *dstpkt, cfpkt_t *addpkt, uint16 expectlen)
+{
+	uint16 addpktlen = addpkt->_tail_ - addpkt->_data_;
+	uint16 neededtailspace;
+	CHECK_MAGIC(dstpkt);
+	CHECK_MAGIC(addpkt);
+	if (expectlen > addpktlen)
+		neededtailspace = expectlen;
+	else
+		neededtailspace = addpktlen;
+	if (dstpkt->_tail_ + neededtailspace > dstpkt->_end_) {
+		cfpkt_t *tmppkt;
+		uint16 dstlen;
+		uint16 createlen;
+		dstlen = dstpkt->_tail_ - dstpkt->_data_;
+		createlen = dstlen + addpktlen;
+		if (expectlen > createlen)
+			createlen = expectlen;
+		tmppkt = cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX);
+		tmppkt->_tail_ = tmppkt->_data_ + dstlen;
+		memcpy(tmppkt->_data_, dstpkt->_data_, dstlen);
+		cfpkt_destroy(dstpkt);
+		dstpkt = tmppkt;
+	}
+	memcpy(dstpkt->_tail_, addpkt->_data_,
+	       addpkt->_tail_ - addpkt->_data_);
+	cfpkt_destroy(addpkt);
+	dstpkt->_tail_ += addpktlen;
+	CHECK_MAGIC(dstpkt);
+	return dstpkt;
+}
+
+cfpkt_t *cfpkt_split(cfpkt_t *pkt, uint16 pos)
+{
+	cfpkt_t *half;		/* FIXME: Rename half to pkt2 */
+	uint8 *split = pkt->_data_ + pos;
+	uint16 len2nd = pkt->_tail_ - split;
+	CFLOG_TRACE3(("cfpkt_split(%p,%d)", (void *) pkt, pos));
+
+
+	CHECK_MAGIC(pkt);
+	if (pkt->_data_ + pos > pkt->_tail_) {
+		PKT_ERROR(pkt,
+			  "cfpkt_split: trying to split beyond end of packet");
+		return 0;
+	}
+
+	/* Create a new packet and */
+	half = cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX, PKT_PREFIX);
+
+	CFLOG_TRACE3(("halfpkt=%p", (void *) half));
+
+	if (half == NULL)
+		return NULL;
+
+	/* Reduce the length of the original packet */
+	pkt->_tail_ = split;
+
+	memcpy(half->_data_, split, len2nd);
+	half->_tail_ += len2nd;
+	CHECK_MAGIC(pkt);
+	return half;
+}
+
+bool cfpkt_erroneous(cfpkt_t *pkt)
+{
+	/* Errors are marked by setting _end_ equal to _head_ (zero sized
+	   packet) */
+	return pkt->_end_ == (uint8 *) pkt->_head_;
+}
+
+bool cfpkt_pad_trail(cfpkt_t *pkt, uint16 len)
+{
+	CHECK_MAGIC(pkt);
+	if (pkt->_tail_ + len > pkt->_end_) {
+		PKT_ERROR(pkt, "cfpkt_pad_trail pads beyond end of packet");
+		return false;
+	}
+#if 1
+	/* We're assuming that the modem don't require zero-padding */
+	pkt->_tail_ += len;
+#else
+	while (len--)
+		*pkt->_tail_++ = 0;
+#endif
+
+	CHECK_MAGIC(pkt);
+	return true;
+}
+
+bool cfpkt_peek_head(cfpkt_t *const pkt, void *dta, uint16 len)
+{
+	register int i;
+	uint8 *data = (uint8 *) dta;
+	CHECK_MAGIC(pkt);
+	if (pkt->_data_ + len > pkt->_tail_) {
+		PKT_ERROR(pkt,
+			  "cfpkt_peek_head would read beyond end of packet");
+		return false;
+	}
+	for (i = 0; i < len; i++)
+		data[i] = pkt->_data_[i];
+	CHECK_MAGIC(pkt);
+	return true;
+
+}
+
+
+
+int cfpkt_raw_append(cfpkt_t *cfpkt, void **buf, unsigned int buflen)
+{
+	cfglu_assert(buf != NULL);
+	if (cfpkt->_tail_ + buflen > cfpkt->_end_) {
+		PKT_ERROR(cfpkt,
+			  "cfpkt_raw_append would append beyond end of packet");
+		return false;
+	}
+
+	*buf = cfpkt->_tail_;
+	cfpkt->_tail_ += buflen;
+	return true;
+}
+
+int cfpkt_raw_extract(cfpkt_t *cfpkt, void **buf, unsigned int buflen)
+{
+	cfglu_assert(buf != NULL);
+	if (cfpkt->_data_ + buflen > cfpkt->_tail_) {
+		PKT_ERROR(cfpkt,
+			  "cfpkt_raw_extact would read beyond end of packet");
+		return false;
+	}
+
+	*buf = cfpkt->_data_;
+	cfpkt->_data_ += buflen;
+	return true;
+}
+
+
+
+
+cfpktq_t *cfpkt_queuecreate()
+{
+	cfpktq_t *q = (cfpktq_t *) cfglu_alloc(sizeof(cfpktq_t));
+	cfglu_init_lock(q->qlock);
+	q->head = NULL;
+	return q;
+}
+
+void cfpkt_queue(cfpktq_t *pktq, cfpkt_t *pkt, unsigned short prio)
+{
+	CHECK_MAGIC(pkt);
+	cfglu_lock(pktq->qlock);
+	pkt->next = NULL;
+	if (pktq->head == NULL)
+		pktq->head = pkt;
+	else {
+		/* NOTE: Consider having a tail pointer in order to improve
+		   performance */
+		cfpkt_t *p = pktq->head;
+		while (p->next != NULL) {
+			CHECK_MAGIC(p);
+			p = p->next;
+		}
+		p->next = pkt;
+	}
+	cfglu_unlock(pktq->qlock);
+}
+
+cfpkt_t *cfpkt_qpeek(cfpktq_t *pktq)
+{
+	cfpkt_t *pkt;
+
+	cfglu_lock(pktq->qlock);
+	if (pktq->head != NULL) {
+		/* NOTE: Sync is only needed due to this CHECK_MAGIC... */
+		CHECK_MAGIC(pktq->head);
+	}
+	pkt = pktq->head;
+	cfglu_unlock(pktq->qlock);
+	return pkt;
+}
+
+cfpkt_t *cfpkt_dequeue(cfpktq_t *pktq)
+{
+	cfpkt_t *ret;
+	cfglu_lock(pktq->qlock);
+	if (pktq->head == NULL) {
+		cfglu_unlock(pktq->qlock);
+		return NULL;
+	}
+	ret = pktq->head;
+	pktq->head = pktq->head->next;
+	CHECK_MAGIC(ret);
+	cfglu_unlock(pktq->qlock);
+	return ret;
+}
+
+caif_packet_funcs_t cfpkt_get_packet_funcs()
+{
+	caif_packet_funcs_t f;
+	memset(&f,0,sizeof(f));
+	f.cfpkt_destroy = cfpkt_destroy;
+	f.cfpkt_extract = cfpkt_extract;
+	f.cfpkt_create_xmit_pkt = cfpkt_create_uplink;	/* FIXME: Decide upon
+							   which create
+							   functions to export
+							 */
+	f.cfpkt_create_recv_pkt = cfpkt_create_uplink;
+	f.cfpkt_raw_append = cfpkt_raw_append;
+	f.cfpkt_raw_extract = cfpkt_raw_extract;
+	f.cfpktq_create = cfpkt_queuecreate;
+	f.cfpkt_queue = cfpkt_queue;
+	f.cfpkt_qpeek = cfpkt_qpeek;
+	f.cfpkt_dequeue = cfpkt_dequeue;
+	f.cfpkt_getlen = cfpkt_getlen;
+	return f;
+}
diff --git a/net/caif/generic/cfpkt_skbuff.c b/net/caif/generic/cfpkt_skbuff.c
new file mode 100644
index 0000000..def6880
--- /dev/null
+++ b/net/caif/generic/cfpkt_skbuff.c
@@ -0,0 +1,585 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+
+
+
+
+
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/hardirq.h>
+
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfpkt.h>
+
+/* Maximum size of CAIF header */
+#define PKT_PREFIX CAIF_NEEDED_HEADROOM
+
+/* Maximum size of CAIF trailer */
+#define PKT_POSTFIX CAIF_NEEDED_TAILROOM
+
+#define PKT_LEN_WHEN_EXTENDING 128
+
+#define CFPKT_PRIV_DATA(pkt) ((struct cfpkt_priv_data_t *) (&pkt->skb.cb[0]))
+
+#define PKT_ERROR(pkt, errmsg) do {        \
+    CFPKT_PRIV_DATA(pkt)->erronous = true; \
+    skb_reset_tail_pointer(&pkt->skb);     \
+    CFLOG_WARN((errmsg));                  \
+  } while (0)
+
+#ifdef CFKPKT_PACKET_DUMP
+char pkt_debug_buffer[256];
+#define pkt_dump_debug(pkt) do {                                        \
+    cfpkt_log_pkt((pkt), pkt_debug_buffer, 250);                        \
+    printk(KERN_DEBUG "%d: nonlinear: %s, fp=%s %s",                    \
+	__LINE__,                                                    \
+	skb_is_nonlinear(&(pkt)->skb) ? "true" : "false",            \
+	CFPKT_PRIV_DATA((pkt))->fastpath ? "true" : "false",         \
+	pkt_debug_buffer);                                           \
+  } while (0)
+#else
+#define pkt_dump_debug(pkt)
+#endif
+
+struct _cfpktq_t {
+	struct sk_buff_head queue;
+};
+
+/* _cfpkt_t is (memory-wise) an sk_buff, but _cfpkt_t is forward declared in
+   cfpkt.h, so we do it this way (instead if typedef): */
+struct _cfpkt_t {
+	struct sk_buff skb;
+};
+
+
+/* Private data inside SKB */
+struct cfpkt_priv_data_t {
+	bool erronous;
+	/*!<Indicate fastpath, buffer has large enough head and tail room
+	   so boundary checks are skipped. */
+	bool fastpath;
+};
+
+cfglu_atomic_t cfpkt_packet_count;
+
+cfpkt_t *cfpkt_fromnative(caif_direction_t dir, void *nativepkt)
+{
+	cfpkt_t *pkt = (cfpkt_t *) nativepkt;
+
+	/* In Linux, "native" is always sk_buff: */
+	struct sk_buff *skb = (struct sk_buff *) nativepkt;
+
+	CFPKT_PRIV_DATA(pkt)->erronous = false;
+
+	/* Set Fastpath if we have enough head room */
+	if (likely(dir == CAIF_DIR_OUT && !skb_is_nonlinear(skb)
+		   && skb_headroom(skb) >= PKT_PREFIX
+		   && skb_tailroom(skb) >= PKT_POSTFIX))
+		CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	else if (likely(dir == CAIF_DIR_IN && !skb_is_nonlinear(skb)
+			&& skb_headlen(skb) > PKT_PREFIX + PKT_POSTFIX))
+		CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	else
+		CFPKT_PRIV_DATA(pkt)->fastpath = false;
+
+	CFLOG_TRACE3(("cfpkt_fromnative: fastpath=%s",
+		      CFPKT_PRIV_DATA(pkt)->fastpath ? "true" : "false"));
+	cfglu_atomic_inc(cfpkt_packet_count);
+
+	pkt_dump_debug(pkt);
+	return pkt;
+}
+
+
+inline void *cfpkt_tonative(cfpkt_t *pkt)
+{
+	/* In Linux, "native" is always sk_buff: */
+	pkt_dump_debug(pkt);
+	return (void *) pkt;
+}
+
+
+cfpkt_t *cfpkt_create_pfx(uint16 len, uint16 pfx)
+{
+	struct sk_buff *skb;
+
+	if (likely(in_interrupt()))
+		skb = alloc_skb(len + pfx, GFP_ATOMIC);
+	else
+		skb = alloc_skb(len + pfx, GFP_KERNEL);
+
+	if (unlikely(skb == NULL))
+		return NULL;
+
+	skb_reserve(skb, pfx);
+	cfglu_atomic_inc(cfpkt_packet_count);
+	return (cfpkt_t *) skb;
+}
+
+inline cfpkt_t *cfpkt_create(uint16 len)
+{
+	cfpkt_t *r = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+	CFPKT_PRIV_DATA(r)->fastpath = true;
+
+	pkt_dump_debug(r);
+	return r;
+}
+
+void cfpkt_destroy(cfpkt_t *pkt)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	cfglu_atomic_dec(cfpkt_packet_count);
+	cfglu_assert(cfglu_atomic_read(cfpkt_packet_count) >= 0);
+	kfree_skb(skb);
+}
+
+inline bool cfpkt_more(cfpkt_t *pkt)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	return skb->len > 0;
+}
+
+bool cfpkt_peek_head(cfpkt_t *pkt, void *data, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	pkt_dump_debug(pkt);
+	if (likely(CFPKT_PRIV_DATA(pkt)->fastpath)) {
+		memcpy(data, skb->data, len);
+		pkt_dump_debug(pkt);
+		return true;
+	}
+	return cfpkt_extr_head(pkt, data, len) &&
+	    cfpkt_add_head(pkt, data, len);
+}
+
+bool cfpkt_extr_head(cfpkt_t *pkt, void *data, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	uint8 *from;
+	pkt_dump_debug(pkt);
+
+	if (unlikely(len > skb->len)) {
+		PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n");
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+
+	if (unlikely(!(CFPKT_PRIV_DATA(pkt)->fastpath) &&
+		     (len > skb_headlen(skb)))) {
+		if (unlikely(skb_linearize(skb) != 0)) {
+			CFPKT_PRIV_DATA(pkt)->erronous = true;
+			return false;
+		}
+	}
+
+	from = skb_pull(skb, len);
+	from -= len;
+	memcpy(data, from, len);
+	pkt_dump_debug(pkt);
+	return true;
+}
+
+bool cfpkt_extr_trail(cfpkt_t *pkt, void *dta, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	uint8 *data = dta;
+	uint8 *from;
+	pkt_dump_debug(pkt);
+	if (unlikely(skb_linearize(skb) != 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+	pkt_dump_debug(pkt);
+	if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
+		PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n");
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+	from = skb_tail_pointer(skb) - len;
+	skb_trim(skb, skb->len - len);
+	pkt_dump_debug(pkt);
+	memcpy(data, from, len);
+	return true;
+}
+
+bool cfpkt_pad_trail(cfpkt_t *pkt, uint16 len)
+{
+	return cfpkt_add_body(pkt, NULL, len);
+}
+
+bool cfpkt_add_body(cfpkt_t *pkt, const void *data, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	struct sk_buff *lastskb;
+	uint8 *to;
+	uint16 addlen = 0;
+
+	pkt_dump_debug(pkt);
+
+	lastskb = skb;
+
+	/* Do we need to add space at the tail? */
+	if (unlikely(skb_tailroom(skb) < len)) {
+		if (likely(len < PKT_LEN_WHEN_EXTENDING))
+			addlen = PKT_LEN_WHEN_EXTENDING;
+		else
+			addlen = len;
+	}
+
+	/* Do we need to change the skb before writing to the tail? */
+	if (unlikely((addlen > 0) || skb_cloned(skb) || skb_shared(skb))) {
+
+		/* Make sure data is writable */
+		if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
+			CFPKT_PRIV_DATA(pkt)->erronous = true;
+			return false;
+		}
+
+		/* Is the skb non-linear after skb_cow_data()? If so, we are
+		   going to add data to the last skb, so we need to adjust
+		   lengths of the top skb. */
+		if (lastskb != skb) {
+			skb->len += len;
+			skb->data_len += len;
+		}
+	}
+
+	/* All set to put the last skb and optionally write data there. */
+	to = skb_put(lastskb, len);
+	if (likely(data))
+		memcpy(to, data, len);
+	pkt_dump_debug(pkt);
+	return true;
+}
+inline bool cfpkt_addbdy(cfpkt_t *pkt, uint8 data)
+{
+	return cfpkt_add_body(pkt, &data, 1);
+}
+
+bool cfpkt_add_head(cfpkt_t *pkt, const void *data2, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	struct sk_buff *lastskb;
+	uint8 *to;
+	const uint8 *data = data2;
+	pkt_dump_debug(pkt);
+	if (unlikely(skb_headroom(skb) < len)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+
+	/* Make sure data is writable */
+	if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return false;
+	}
+
+	to = skb_push(skb, len);
+	memcpy(to, data, len);
+	pkt_dump_debug(pkt);
+	return true;
+}
+
+inline bool cfpkt_add_trail(cfpkt_t *pkt, const void *data, uint16 len)
+{
+	return cfpkt_add_body(pkt, data, len);
+}
+
+inline uint16 cfpkt_getlen(cfpkt_t *pkt)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	return skb->len;
+}
+
+inline uint16 cfpkt_iterate(cfpkt_t *pkt, iterfunc_t func, uint16 data)
+{
+
+	/* Don't care about the performance hit of linearizing,
+	 * Checksum should not be used on high-speed interfaces anyway.*/
+	if (unlikely(skb_linearize(&pkt->skb) != 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return 0;
+	}
+	return func(data, pkt->skb.data, cfpkt_getlen(pkt));
+}
+
+int cfpkt_setlen(cfpkt_t *pkt, uint16 len)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+
+	pkt_dump_debug(pkt);
+
+	if (likely(len <= skb->len)) {
+		if (unlikely(skb->data_len))
+			___pskb_trim(skb, len);
+		else
+			skb_trim(skb, len);
+
+		pkt_dump_debug(pkt);
+		return cfpkt_getlen(pkt);
+	}
+
+	/* Need to expand skb */
+	if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+
+	pkt_dump_debug(pkt);
+	return cfpkt_getlen(pkt);
+}
+
+void
+cfpkt_extract(cfpkt_t *cfpkt, void *buf, unsigned int buflen,
+	      unsigned int *actual_len)
+{
+	uint16 pklen;
+
+	pkt_dump_debug(cfpkt);
+	pklen = cfpkt_getlen(cfpkt);
+	if (likely(buflen < pklen))
+		pklen = buflen;
+	*actual_len = pklen;
+	cfpkt_extr_head(cfpkt, buf, pklen);
+	pkt_dump_debug(cfpkt);
+}
+
+cfpkt_t *cfpkt_create_uplink(const unsigned char *data, unsigned int len)
+{
+	cfpkt_t *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+	CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	if (unlikely(data != NULL))
+		cfpkt_add_body(pkt, data, len);
+	return pkt;
+}
+
+cfpkt_t *cfpkt_append(cfpkt_t *dstpkt, cfpkt_t *addpkt, uint16 expectlen)
+{
+	struct sk_buff *dst = (struct sk_buff *) dstpkt;
+	struct sk_buff *add = (struct sk_buff *) addpkt;
+	struct sk_buff *lastskb;
+	CFPKT_PRIV_DATA(addpkt)->fastpath = false;
+	CFPKT_PRIV_DATA(dstpkt)->fastpath = false;
+	pkt_dump_debug(dstpkt);
+	pkt_dump_debug(addpkt);
+
+	printk("cfpkt_append() called\n");
+
+	/* Could we (instead of calling skb_cow_data()) check for
+	   cloned || shared and if true allocate a new skb
+	   with an empty head and set skb_shinfo(skb)->frag_list = add ?
+	   If this is safe, would it be more efficient?
+	 */
+
+	/* Make sure destination skb is writable */
+	if (unlikely(skb_cow_data(dst, 0, &lastskb) < 0)) {
+		CFPKT_PRIV_DATA(dstpkt)->erronous = true;
+		return dstpkt;
+	}
+
+	/* First get the frag_list if any */
+	if (likely(skb_shinfo(dst)->frag_list == NULL))
+		skb_shinfo(dst)->frag_list = add;
+	else {
+		lastskb = skb_shinfo(dst)->frag_list;
+
+		/* Go to the very right in the fragment list */
+		while (lastskb->next)
+			lastskb = lastskb->next;
+
+		lastskb->next = add;
+	}
+
+	/* Update size */
+	dst->data_len += add->len;
+	dst->len += add->len;
+	dst->truesize += add->truesize;
+	pkt_dump_debug(dstpkt);
+	cfglu_atomic_dec(cfpkt_packet_count);
+	return dstpkt;
+}
+
+cfpkt_t *cfpkt_split(cfpkt_t *pkt, uint16 pos)
+{
+	struct sk_buff *skb = (struct sk_buff *) pkt;
+	struct sk_buff *skb2;
+	CFPKT_PRIV_DATA(pkt)->fastpath = false;
+	if (unlikely(pos > skb->len)) {
+		PKT_ERROR(pkt, "cfpkt_split: split beyond end of packet\n");
+		return NULL;
+	}
+	pkt_dump_debug(pkt);
+
+	/* Make sure skb is writable */
+	if (unlikely(skb_cow_data(skb, 0, &skb2) < 0)) {
+		CFPKT_PRIV_DATA(pkt)->erronous = true;
+		return NULL;
+	}
+
+	skb2 = (struct sk_buff *) cfpkt_create(skb->len - pos);
+
+	if (unlikely(skb2 == NULL))
+		return NULL;
+
+	CFPKT_PRIV_DATA(pkt)->fastpath = false;
+	CFPKT_PRIV_DATA(pkt)->erronous = false;
+	pkt_dump_debug((cfpkt_t *) skb2);
+
+	skb_split(skb, skb2, pos);
+
+	pkt_dump_debug((cfpkt_t *) skb2);
+	cfglu_atomic_inc(cfpkt_packet_count);
+	return (cfpkt_t *) skb2;
+}
+
+char *cfpkt_log_pkt(cfpkt_t *cfpkt, char *buf, int buflen)
+{
+	struct sk_buff *skb = (struct sk_buff *) cfpkt;
+	char *p = buf;
+	int i;
+
+	if (skb_linearize(skb) != 0)
+		return NULL;
+
+	sprintf(buf, " pkt:%p len:%d {%d,%d} data: [",
+		skb,
+		skb->tail - skb->data,
+		skb->data - skb->head, skb->tail - skb->head);
+	p = buf + strlen(buf);
+
+	for (i = 0; i < skb->tail - skb->data; i++) {
+		if (p > buf + buflen - 10) {
+			sprintf(p, "...");
+			p = buf + strlen(buf);
+			break;
+		}
+		sprintf(p, "%02x,", skb->data[i]);
+		p = buf + strlen(buf);
+	}
+	sprintf(p, "]\n");
+	return buf;
+}
+
+
+int cfpkt_raw_append(cfpkt_t *cfpkt, void **buf, unsigned int buflen)
+{
+	struct sk_buff *skb = (struct sk_buff *) cfpkt;
+	struct sk_buff *lastskb;
+
+	cfglu_assert(buf != NULL);
+
+	/* Make sure skb is writable */
+	if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	if (unlikely(skb_linearize(skb) != 0)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	if (unlikely(skb_tailroom(skb) < buflen)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	*buf = skb_put(skb, buflen);
+	return 1;
+}
+
+int cfpkt_raw_extract(cfpkt_t *cfpkt, void **buf, unsigned int buflen)
+{
+	struct sk_buff *skb = (struct sk_buff *) cfpkt;
+
+	cfglu_assert(buf != NULL);
+
+	if (unlikely(buflen > skb->len)) {
+		CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+		return 0;
+	}
+
+	if (unlikely(buflen > skb_headlen(skb))) {
+		if (unlikely(skb_linearize(skb) != 0)) {
+			CFPKT_PRIV_DATA(cfpkt)->erronous = true;
+			return 0;
+		}
+	}
+
+	*buf = skb->data;
+	skb_pull(skb, buflen);
+
+	return 1;
+}
+
+
+
+
+inline bool cfpkt_erroneous(cfpkt_t *pkt)
+{
+	return CFPKT_PRIV_DATA(pkt)->erronous;
+}
+
+cfpkt_t *cfpkt_create_pkt(caif_direction_t dir,
+			  const unsigned char *data, unsigned int len)
+{
+	cfpkt_t *pkt;
+	if (dir == CAIF_DIR_OUT)
+		pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+
+	else
+		pkt = cfpkt_create_pfx(len, 0);
+
+	if (unlikely(data))
+		cfpkt_add_body(pkt, data, len);
+	CFPKT_PRIV_DATA(pkt)->fastpath = true;
+	CFPKT_PRIV_DATA(pkt)->erronous = false;
+	return pkt;
+}
+
+caif_packet_funcs_t cfpkt_get_packet_funcs()
+{
+	caif_packet_funcs_t f;
+	f.cfpkt_fromnative = cfpkt_fromnative;
+	f.cfpkt_tonative = cfpkt_tonative;
+	f.cfpkt_destroy = cfpkt_destroy;
+	f.cfpkt_extract = cfpkt_extract;
+	f.cfpkt_create_xmit_pkt = cfpkt_create_uplink;
+	f.cfpkt_create_recv_pkt = cfpkt_create_uplink;
+	f.cfpkt_dequeue = cfpkt_dequeue;
+	f.cfpkt_qpeek = cfpkt_qpeek;
+	f.cfpkt_queue = cfpkt_queue;
+	f.cfpktq_create = cfpkt_queuecreate;
+	f.cfpkt_raw_extract = cfpkt_raw_extract;
+	f.cfpkt_raw_append = cfpkt_raw_append;
+	f.cfpkt_getlen = cfpkt_getlen;
+	return f;
+}
+
+cfpktq_t *cfpkt_queuecreate()
+{
+	struct sk_buff_head *q = cfglu_alloc(sizeof(struct sk_buff_head));
+	skb_queue_head_init(q);
+	return (cfpktq_t *) q;
+}
+
+void cfpkt_queue(cfpktq_t *pktq, cfpkt_t *pkt, unsigned short prio)
+{
+	skb_queue_tail((struct sk_buff_head *) pktq, (struct sk_buff *) pkt);
+}
+
+cfpkt_t *cfpkt_qpeek(cfpktq_t *pktq)
+{
+	return (cfpkt_t *) skb_peek((struct sk_buff_head *) pktq);
+}
+
+cfpkt_t *cfpkt_dequeue(cfpktq_t *pktq)
+{
+	return (cfpkt_t *) skb_dequeue((struct sk_buff_head *) pktq);
+}
diff --git a/net/caif/generic/cfrfml.c b/net/caif/generic/cfrfml.c
new file mode 100644
index 0000000..c722836
--- /dev/null
+++ b/net/caif/generic/cfrfml.c
@@ -0,0 +1,112 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+#define container_obj(layr) cfglu_container_of(layr, cfsrvl_t, layer)
+
+#define RFM_SEGMENTATION_BIT 0x01
+
+#define RFM_PAYLOAD  0x00
+#define RFM_CMD_BIT  0x80
+#define RFM_FLOW_OFF 0x81
+#define RFM_FLOW_ON  0x80
+#define RFM_SET_PIN  0x82
+#define RFM_CTRL_PKT_SIZE 1
+
+static int cfrfml_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfrfml_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt);
+
+layer_t *cfrfml_create(uint8 channel_id, uint8 phyid)
+{
+	cfsrvl_t *rfm = cfglu_alloc(sizeof(cfsrvl_t));
+	cfglu_assert(offsetof(cfsrvl_t, layer) == 0);
+
+	memset(rfm, 0, sizeof(cfsrvl_t));
+	cfsrvl_init(rfm, channel_id, phyid);
+	rfm->layer.receive = cfrfml_receive;
+	rfm->layer.transmit = cfrfml_transmit;
+	sprintf(rfm->layer.name, "rfm%d", channel_id);
+	return &rfm->layer;
+}
+
+void cffrml_destroy(layer_t *layer)
+{
+	cfglu_free(layer);
+}
+
+
+static int cfrfml_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	uint8 tmp;
+	bool segmented;
+	int ret;
+	CFLOG_ENTER(("\n"));
+	cfglu_assert(layr->up != NULL);
+	cfglu_assert(layr->receive != NULL);
+
+
+	/* RFM is taking care of Segmentation, stripping of Segmentation bit */
+	if (!cfpkt_extr_head(pkt, &tmp, 1)) {
+		CFLOG_ERROR(("cfrfml: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPROTO;
+	}
+	segmented = tmp & RFM_SEGMENTATION_BIT;
+	cfglu_assert(!segmented);
+
+	ret = layr->up->receive(layr->up, pkt);
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
+
+static int cfrfml_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt)
+{
+	uint8 tmp = 0;
+	transmt_info info;
+	int ret;
+	cfsrvl_t *service = container_obj(layr);
+
+	cfglu_assert(layr->dn != NULL);
+	cfglu_assert(layr->dn->transmit != NULL);
+
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("packet too large size=%d\n", cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+
+
+	if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("packert too large size=%d\n",
+			     cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+	if (!cfpkt_add_head(pkt, &tmp, 1)) {
+		CFLOG_ERROR(("cffrml: Packet is erroneous!\n"));
+		return CFGLU_EPKT;
+	}
+
+	/* Add info for MUX-layer to route the packet out */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	/* For optimizing alignment we add up the size of CAIF header before
+	   payload */
+	info.hdr_len = 1;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_extr_head(pkt, &tmp, 1);
+	return ret;
+}
diff --git a/net/caif/generic/cfserl.c b/net/caif/generic/cfserl.c
new file mode 100644
index 0000000..1236f5f
--- /dev/null
+++ b/net/caif/generic/cfserl.c
@@ -0,0 +1,297 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+
+#include <net/caif/generic/fcs.h>
+#define container_obj(layr) ((struct cfserl *) layr)
+
+
+#define CFSERL_STX 0x02
+#define CAIF_MINIUM_PACKET_SIZE 4
+struct cfserl {
+	layer_t layer;
+	cfpkt_t *incomplete_frm;
+	cfglu_lock_t sync;
+	bool usestx;
+};
+#define STXLEN(layr) (layr->usestx ? 1 : 0)
+static int cfserl_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfserl_transmit(layer_t *layr, transmt_info *info,
+			   cfpkt_t *pkt);
+static void cfserl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid);
+
+struct cfserl *cfserl_create(int type, int instance, bool use_stx)
+{
+	struct cfserl *this = cfglu_alloc(sizeof(struct cfserl));
+	cfglu_assert(offsetof(struct cfserl, layer) == 0);
+
+	memset(this, 0, sizeof(struct cfserl));
+	this->layer.receive = cfserl_receive;
+	this->layer.transmit = cfserl_transmit;
+	this->layer.ctrlcmd = cfserl_ctrlcmd;
+	this->layer.type = type;
+	this->usestx = use_stx;
+	cfglu_init_lock(this->sync);
+	sprintf(this->layer.name, "ser1");
+	return this;
+}
+
+void cfserl_set_uplayer(struct cfserl *this, layer_t *up)
+{
+	this->layer.up = up;
+}
+
+void cfserl_set_dnlayer(struct cfserl *this, layer_t *dn)
+{
+	this->layer.dn = dn;
+
+}
+
+static int cfserl_receive(layer_t *l, cfpkt_t *newpkt)
+{
+	struct cfserl *layr = container_obj(l);
+	uint16 pkt_len;
+	cfpkt_t *pkt = NULL;
+	cfpkt_t *tail_pkt = NULL;
+	uint8 tmp8;
+	uint16 tmp;
+	uint8 stx = CFSERL_STX;
+	int ret;
+	uint16 expectlen = 0;
+
+
+
+#ifdef CAIF_DEBUG_ON
+	static char buf[10000];
+	uint16 newpktlen = cfpkt_getlen(newpkt);
+	CFLOG_ENTER(("\n"));
+	if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+		cfpkt_log_pkt(newpkt, buf, sizeof(buf));
+		CFLOG_TRACE3(("serl: RECEIVE PACKET %s\n", buf));
+	}
+#endif
+	cfglu_lock(layr->sync);
+
+
+	if (layr->incomplete_frm != NULL) {
+
+		layr->incomplete_frm =
+		    cfpkt_append(layr->incomplete_frm, newpkt, expectlen);
+		CFLOG_TRACE2(("serl: Appending %d bytes, new packet holds %d "
+			      "bytes with expected frame-length=%d\n",
+			      newpktlen,
+			      cfpkt_getlen(layr->incomplete_frm),
+			      expectlen));
+		pkt = layr->incomplete_frm;
+	} else {
+		pkt = newpkt;
+	}
+
+	layr->incomplete_frm = NULL;
+
+
+	do {
+#ifdef CAIF_DEBUG_ON
+		if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+			cfpkt_log_pkt(pkt, buf, sizeof(buf));
+			CFLOG_TRACE3(("serl: PACKET before STX search: %s\n",
+				      buf));
+		}
+#endif
+
+		/*
+		 *  Seach for STX at start of pkt if STX is used
+		 */
+		if (layr->usestx) {
+			CFLOG_TRACE2(("serl: Start looking for STX at "
+				      "start of frame\n"));
+			(void) cfpkt_extr_head(pkt, &tmp8, 1);
+			if (tmp8 != CFSERL_STX) {
+				CFLOG_TRACE(("serl: STX Error! STX not at "
+					     "start of packe\n"));
+				while (cfpkt_more(pkt)
+				       && tmp8 != CFSERL_STX) {
+					(void) cfpkt_extr_head(pkt, &tmp8, 1);
+				}
+				if (!cfpkt_more(pkt)) {
+					CFLOG_TRACE(("serl: Destroying packet "
+						     "when no STX found\n"));
+					cfpkt_destroy(pkt);
+					layr->incomplete_frm = NULL;
+					cfglu_unlock(layr->sync);
+					CFLOG_EXIT(("\n"));
+					return CFGLU_EPROTO;
+				}
+			}
+		}
+
+		pkt_len = cfpkt_getlen(pkt);
+
+		/*
+		 *  pkt_len is the accumulated length of the packet data
+		 *  we have received so far
+		 *  Exit if frame don't hold length.
+		 */
+
+		if (pkt_len < 2) {
+			if (layr->usestx)
+				cfpkt_add_head(pkt, &stx, 1);
+			layr->incomplete_frm = pkt;
+			cfglu_unlock(layr->sync);
+#ifdef CAIF_DEBUG_ON
+			if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+				cfpkt_log_pkt(pkt, buf, sizeof(buf));
+				CFLOG_TRACE3(("serl: PACKET before exit "
+					      "(too short): %s\n", buf));
+			}
+#endif
+
+			CFLOG_EXIT(("\n"));
+			return 0;
+		}
+
+		/*
+		 *  Find length of frame
+		 *  expectlen is the length we need for a full frame.
+		 */
+		(void) cfpkt_peek_head(pkt, &tmp, 2);
+		expectlen = cfglu_le16_to_cpu(tmp) + 2;
+		CFLOG_TRACE2(("serl:  Processing a packet of %d bytes with "
+			      "expected length=%d\n", pkt_len, expectlen));
+
+#ifdef CAIF_DEBUG_ON
+		if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+			cfpkt_log_pkt(pkt, buf, sizeof(buf));
+			CFLOG_TRACE3(("serl: PACKET after STX Seach: %s\n",
+				      buf));
+		}
+#endif
+
+
+
+		/*
+		 * Frame error handling
+		 */
+		if (expectlen < CAIF_MINIUM_PACKET_SIZE
+		    || expectlen > CAIF_MAX_FRAMESIZE) {
+			if (!layr->usestx) {
+				CFLOG_ERROR(("cfserl: packet has bad expectlen "
+					     "%d\n", expectlen));
+				CFLOG_ERROR(("serl: Packet is erroneous throw "
+					     "it away (expectlen=%d, len=%d)",
+					     expectlen, pkt_len));
+				if (pkt != NULL)
+					cfpkt_destroy(pkt);
+				layr->incomplete_frm = NULL;
+				expectlen = 0;
+				cfglu_unlock(layr->sync);
+				CFLOG_EXIT(("\n"));
+				return CFGLU_EPROTO;
+			}
+			continue;
+		}
+
+
+		if (pkt_len < expectlen) {
+			/* Too little received data */
+			CFLOG_TRACE2(("serl: Holding incomplete packet with "
+				      "current length=%d and expected "
+				      "length=%d", pkt_len, expectlen));
+			if (layr->usestx)
+				cfpkt_add_head(pkt, &stx, 1);
+
+#ifdef CAIF_DEBUG_ON
+			if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+				cfpkt_log_pkt(pkt, buf, sizeof(buf));
+				CFLOG_TRACE3(("serl: incomplete_frame: %s\n",
+					      buf));
+			}
+#endif
+			layr->incomplete_frm = pkt;
+			cfglu_unlock(layr->sync);
+			return 0;
+		}
+
+		/* Enough data for at least one frame */
+		/* Split the frame, if too long */
+		if (pkt_len > expectlen) {
+			CFLOG_TRACE2(("serl: Splitting too long packet of "
+				      "length = %d and frame size =%d\n",
+				      pkt_len, expectlen));
+			tail_pkt = cfpkt_split(pkt, expectlen);
+		} else {
+			tail_pkt = NULL;
+		}
+
+#ifdef CAIF_DEBUG_ON
+		if (caif_dbg_level > CFLOG_LEVEL_TRACE3) {
+			cfpkt_log_pkt(pkt, buf, sizeof(buf));
+			CFLOG_TRACE3(("serl: PACKET sent up: %s\n", buf));
+		}
+#endif
+
+		/* Send the first part of packet upwards */
+		ret = layr->layer.up->receive(layr->layer.up, pkt);
+
+		if (ret == CFGLU_EFCS) {
+			CFLOG_ERROR(("cfserl: upper layer return error: %d\n",
+				     ret));
+
+			if (layr->usestx) {
+				CFLOG_WARN(("cfserl: Layer above return fcs "
+					    "error, Search for next STX\n"));
+				if (tail_pkt != NULL)
+					pkt = cfpkt_append(pkt, tail_pkt, 0);
+
+				/* Start seach for next STX if frame failed */
+				continue;
+			} else {
+				cfpkt_destroy(pkt);
+				pkt = NULL;
+			}
+		}
+
+		pkt = tail_pkt;
+
+	} while (pkt != NULL);
+
+
+
+	cfglu_unlock(layr->sync);
+	return 0;
+
+}
+
+static int cfserl_transmit(layer_t *layer, transmt_info *info,
+			   cfpkt_t *newpkt)
+{
+	struct cfserl *layr = container_obj(layer);
+	int ret;
+	uint8 tmp8 = CFSERL_STX;
+	CFLOG_ENTER(("\n"));
+	if (layr->usestx)
+		cfpkt_add_head(newpkt, &tmp8, 1);
+	ret = layer->dn->transmit(layer->dn, info, newpkt);
+	if (ret < 0)
+		cfpkt_extr_head(newpkt, &tmp8, 1);
+
+	CFLOG_EXIT(("\n"));
+	return ret;
+}
+
+static void cfserl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	layr->up->ctrlcmd(layr->up, ctrl, phyid);
+}
diff --git a/net/caif/generic/cfshml.c b/net/caif/generic/cfshml.c
new file mode 100644
index 0000000..378864f
--- /dev/null
+++ b/net/caif/generic/cfshml.c
@@ -0,0 +1,67 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+
+
+static int cfshml_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfshml_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt);
+static void cfshml_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid);
+
+layer_t *cfshml_create(int type, int instance)
+{
+	layer_t *this = cfglu_alloc(sizeof(layer_t));
+
+	memset(this, 0, sizeof(layer_t));
+	this->receive = cfshml_receive;
+	this->transmit = cfshml_transmit;
+	this->ctrlcmd = cfshml_ctrlcmd;
+	this->type = type;
+	sprintf(this->name, "shm1");
+	return this;
+}
+
+void cfshml_set_uplayer(layer_t *this, layer_t *up)
+{
+	this->up = up;
+}
+
+void cfshml_set_dnlayer(layer_t *this, layer_t *dn)
+{
+	this->dn = dn;
+	this->dn->type = this->type;
+}
+
+static int cfshml_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	int ret;
+	/* Send the first part of packet upwards */
+	ret = layr->up->receive(layr->up, pkt);
+	/* FCS Error don't delete the packet */
+	if (ret == CFGLU_EFCS)
+		cfpkt_destroy(pkt);
+	return ret;
+}
+
+static int cfshml_transmit(layer_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	return layr->dn->transmit(layr->dn, info, pkt);
+}
+
+static void cfshml_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	layr->up->ctrlcmd(layr->up, ctrl, phyid);
+}
diff --git a/net/caif/generic/cfspil.c b/net/caif/generic/cfspil.c
new file mode 100644
index 0000000..a94a39d
--- /dev/null
+++ b/net/caif/generic/cfspil.c
@@ -0,0 +1,245 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+/** \page CFSPIL - CAIF SPI Layer:
+
+ *  \note: A special protocol is defined for SPI PHYSICAL layer:
+ *              -# CAIF packet is sent by \ref transmit_cb_t "transmit function"
+ *              -# SPI PHY layer will send  \ref ctrlcmd_cb_t "flowcontrol"
+ *                  \ref CAIF_CTRLCMD_FLOW_OFF_IND "off"  upwards in CAIF stack.
+ *              -# CAIF will start appending CAIF Packets upto maximum size.
+ *              -# SPI PHY layer will send  \ref ctrlcmd_cb_t "flowcontrol"
+ *                  \ref CAIF_CTRLCMD_FLOW_ON_IND "on"  upwards in CAIF stack.
+ *              -# Appended CAIF packets are sent by \ref transmit_cb_t
+ *                 "transmit" function.
+
+ */
+
+#include <net/caif/generic/cfspil.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/fcs.h>
+#define CAIF_MAX_SPI_FRAME 4096
+struct _cfspil_t {
+	layer_t layer;		/* The Layer Structure must always be present,
+				   first in struct */
+	uint16 headalignment;	/* Current head alignment: 0 for byte
+				   alignment, 1 for 16bits, 2 for 32bits */
+	uint16 tailalignment;	/* Current tail alignment: 0 for byte
+				   alignment, 1 for 16bits, 2 for 32bits */
+	cfpkt_t *xmitpkt;	/* Pending packet to be sent */
+	cfglu_lock_t sync;
+	cfpktq_t *queue;
+
+};
+
+/* Prototype declarations */
+static int cfspil_receive(cfspil_t *layr, cfpkt_t *pkt);
+static int cfspil_transmit(cfspil_t *layr, transmt_info *info, cfpkt_t *pkt);
+
+layer_t *cfspil_create(int type, int instance)
+{
+	cfspil_t *this = cfglu_alloc(sizeof(cfspil_t));
+	cfglu_assert(offsetof(cfspil_t, layer) == 0);
+	memset(this, 0, sizeof(cfspil_t));
+	cfglu_init_lock(this->sync);
+	this->layer.receive = (receive_cb_t) cfspil_receive;
+	this->layer.transmit = (transmit_cb_t) cfspil_transmit;
+	this->headalignment = 1;
+	this->tailalignment = 1;
+	this->xmitpkt = NULL;	/* Pending packet to be sent */
+	this->layer.type = type;
+	sprintf(this->layer.name, "spi1");
+	this->queue = cfpkt_queuecreate();
+	return &this->layer;
+}
+
+static int cfspil_receive(cfspil_t *layr, cfpkt_t *pkt)
+{
+	uint8 startpad;
+	uint8 pad[16];
+	uint16 len, tmplen;
+	uint16 pktlen;
+	uint16 endpad;
+	int ret;
+	cfpkt_t *nextpkt = NULL;
+
+	while (pkt && cfpkt_more(pkt)) {
+
+		/* Read and handle start offset */
+		(void) cfpkt_extr_head(pkt, &startpad, 1);
+		if (startpad > 3) {
+			CFLOG_ERROR(("cfspil: Received start padding = %d,"
+				     " expected 3 as max\n", startpad));
+			goto error;
+		}
+
+		cfglu_assert(startpad < 16);
+
+		if (startpad)
+			(void) cfpkt_extr_head(pkt, &pad, startpad);
+
+		pktlen = cfpkt_getlen(pkt);
+
+		/* Read packet length */
+		(void) cfpkt_peek_head(pkt, &tmplen, 2);
+		len = cfglu_le16_to_cpu(tmplen) + 2;
+		if (cfpkt_erroneous(pkt) || len < 6
+		    || len > CAIF_MAX_SPI_FRAME || pktlen < len) {
+			CFLOG_ERROR(("cfspil: Packet is erroneous throw it "
+				     " away (len=%d)\n", len));
+			cfpkt_destroy(pkt);
+			return CFGLU_EPROTO;
+		}
+
+
+		/* Compute tail offset i.e. number of bytes to add to ge
+		   alignment */
+		endpad = (len + startpad + 1) & layr->tailalignment;
+
+		/* CFLOG_TRACE(("cfspil: recv pkt:0x%x len:%d startpad:%d
+		   endpad:%d\n", pkt, len, startpad, endpad)); */
+
+		nextpkt = NULL;
+		if (pktlen - len > 5)
+			nextpkt = cfpkt_split(pkt, len);
+
+		if (cfpkt_erroneous(pkt)) {
+			CFLOG_ERROR(("cfspil: Packet is erroneous!\n"));
+			goto error;
+		}
+
+		if (endpad && nextpkt)
+			(void) cfpkt_extr_head(nextpkt, &pad, endpad);
+
+
+		ret = layr->layer.up->receive(layr->layer.up, pkt);
+		/* FCS Error don't delete the packet */
+		if (ret == CFGLU_EFCS)
+			cfpkt_destroy(pkt);
+
+		pkt = nextpkt;
+		nextpkt = NULL;
+	}
+	return 0;
+error:
+	cfpkt_destroy(pkt);
+	if (nextpkt)
+		cfpkt_destroy(nextpkt);
+	return CFGLU_EPROTO;
+}
+
+static cfpkt_t *cfspil_built_xmit_pkt(cfspil_t *layr)
+{
+	uint16 totallen;
+	cfpkt_t *pkt, *xmitpkt;
+
+
+	cfglu_lock(layr->sync);
+	xmitpkt = cfpkt_dequeue(layr->queue);
+
+	/* CFLOG_TRACE(("cfspil_xmitlen - 1: lyr:0x%x,
+	   xmitpkt:0x%x\n", layr, xmitpkt)); */
+
+	if (xmitpkt == NULL) {
+		cfglu_unlock(layr->sync);
+		return NULL;
+	}
+
+	totallen = cfpkt_getlen(xmitpkt);
+	/* CFLOG_TRACE(("cfspil_xmitlen -2 : xmitpkt:0x%x
+	   len:%d\n", xmitpkt, totallen)); */
+
+	while (xmitpkt != NULL && !cfpkt_erroneous(xmitpkt)) {
+		int len;
+		pkt = cfpkt_qpeek(layr->queue);
+
+		len = pkt == NULL ? 0 : cfpkt_getlen(pkt);
+		if (pkt != NULL && totallen + len < CAIF_MAX_SPI_FRAME) {
+			pkt = cfpkt_dequeue(layr->queue);
+			/* CFLOG_TRACE(("cfspil_xmitlen - 3: pkt:0x%x
+			   len:%d\n", pkt, len)); */
+			totallen += len;
+			xmitpkt = cfpkt_append(xmitpkt, pkt, 0);
+			/* CFLOG_TRACE(("cfspil_xmitlen - 4: pkt:0x%x
+			   len:%d\n", xmitpkt, totallen)); */
+		} else {
+			cfglu_unlock(layr->sync);
+			/* CFLOG_TRACE(("cfspil_xmitlen - 5: pkt:0x%x
+			   len:%d\n", xmitpkt, totallen)); */
+
+			return xmitpkt;
+		}
+	}
+
+	cfglu_unlock(layr->sync);
+
+	/* error handling */
+	if (xmitpkt != NULL)
+		cfpkt_destroy(xmitpkt);
+
+	return NULL;
+}
+
+int cfspil_xmitlen(cfspil_t *layr)
+{
+	if (layr->xmitpkt == NULL)
+		layr->xmitpkt = cfspil_built_xmit_pkt(layr);
+
+	/* CFLOG_TRACE(("cfspil_xmitlen: lyr:0x%x\n", layr)); */
+
+	if (layr->xmitpkt != NULL)
+		return cfpkt_getlen(layr->xmitpkt);
+	return 0;
+}
+
+cfpkt_t *cfspil_getxmitpkt(cfspil_t *layr)
+{
+	cfpkt_t *ret = layr->xmitpkt;
+	layr->xmitpkt = NULL;
+	return ret;
+}
+
+static int cfspil_transmit(cfspil_t *layr, transmt_info *info, cfpkt_t *pkt)
+{
+	uint32 pad = -1;
+	uint8 startpad;
+	/* uint16 endpad; */
+	uint16 len;
+	/* CFLOG_TRACE(("cfspil_transmit: lyr:0x%x, pkt:0x%x
+	   pktlen:%d\n", layr, pkt, cfpkt_getlen(pkt))); */
+	startpad = (info->hdr_len + 1) & layr->headalignment;
+	if (startpad)
+		cfpkt_add_head(pkt, &pad, startpad);
+	cfpkt_add_head(pkt, &startpad, 1);
+	len = cfpkt_getlen(pkt);
+
+	/* This should be a compile time option along with all other
+	 * gory SPI details. */
+
+	/* endpad = len & layr->tailalignment; if (endpad)
+	 * cfpkt_pad_trail(pkt, endpad);  */
+
+	if (cfpkt_erroneous(pkt)) {
+		CFLOG_ERROR(("cfspil: Packet is erroneous!\n"));
+		return CFGLU_EPROTO;
+	}
+
+	cfglu_lock(layr->sync);
+	cfpkt_queue(layr->queue, pkt, info->prio);
+	cfglu_unlock(layr->sync);
+
+	/* Inidicate a transmit request, but SPI-PHY pull the packet */
+	layr->layer.dn->transmit(layr->layer.dn, NULL, NULL);
+
+	return 0;
+}
diff --git a/net/caif/generic/cfsrvl.c b/net/caif/generic/cfsrvl.c
new file mode 100644
index 0000000..d48835e
--- /dev/null
+++ b/net/caif/generic/cfsrvl.c
@@ -0,0 +1,177 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define SRVL_CTRL_PKT_SIZE 1
+#define SRVL_FLOW_OFF 0x81
+#define SRVL_FLOW_ON  0x80
+#define SRVL_SET_PIN  0x82
+#define SRVL_CTRL_PKT_SIZE 1
+
+#define container_obj(layr) cfglu_container_of(layr, cfsrvl_t, layer)
+
+static void cfservl_ctrlcmd(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	cfsrvl_t *service = container_obj(layr);
+	cfglu_assert(layr->up != NULL);
+	cfglu_assert(layr->up->ctrlcmd != NULL);
+	CFLOG_ENTER(("\n"));
+	switch (ctrl) {
+	case CAIF_CTRLCMD_INIT_RSP:
+		CFLOG_TRACE(("cfsrvl: ctrlcmd SEND_FLOW_INIT\n"));
+		service->open = true;
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		break;
+	case CAIF_CTRLCMD_DEINIT_RSP:
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+		CFLOG_TRACE(("cfsrvl: ctrlcmd DEINIT_RSP / INIT_FAIL_RSP\n"));
+		service->open = false;
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		break;
+	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
+		if (phyid != service->phid)
+			break;
+		if (service->modem_flow_on)
+			layr->up->ctrlcmd(layr->up,
+					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
+		service->phy_flow_on = false;
+		break;
+	case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
+		if (phyid != service->phid)
+			return;
+		if (service->modem_flow_on) {
+			layr->up->ctrlcmd(layr->up,
+					   CAIF_CTRLCMD_FLOW_ON_IND,
+					   phyid);
+		}
+		service->phy_flow_on = true;
+		break;
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+		if (service->phy_flow_on) {
+			layr->up->ctrlcmd(layr->up,
+					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
+		}
+		service->modem_flow_on = false;
+		break;
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+		if (service->phy_flow_on) {
+			layr->up->ctrlcmd(layr->up,
+					  CAIF_CTRLCMD_FLOW_ON_IND, phyid);
+		}
+		service->modem_flow_on = true;
+		break;
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		break;
+	default:
+		CFLOG_WARN(("cfsrvl: Unexpected ctrl in cfsrvl (%d)\n", ctrl));
+
+		/* We have both modem and phy flow on, send flow on */
+		layr->up->ctrlcmd(layr->up, ctrl, phyid);
+		service->phy_flow_on = true;
+		break;
+	}
+	CFLOG_EXIT(("\n"));
+}
+
+static int cfservl_modemcmd(layer_t *layr, caif_modemcmd_t ctrl)
+{
+	cfsrvl_t *service = container_obj(layr);
+	cfglu_assert(layr != NULL);
+	cfglu_assert(layr->dn != NULL);
+	cfglu_assert(layr->dn->transmit != NULL);
+	switch (ctrl) {
+	case CAIF_MODEMCMD_FLOW_ON_REQ:
+		{
+			cfpkt_t *pkt;
+			transmt_info info;
+			uint8 flow_on = SRVL_FLOW_ON;
+			memset(&info, 0, sizeof(info));
+			info.channel_id = service->layer.id;
+			info.phid = service->phid;
+			info.hdr_len = 1;
+			CFLOG_TRACE(("cfsrvl: ctrlcmd SEND_FLOW_ON\n"));
+			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+			if (!cfpkt_add_head(pkt, &flow_on, 1)) {
+				CFLOG_ERROR(("cfsrvl: Packet is erroneous!\n"));
+				cfpkt_destroy(pkt);
+				return CFGLU_EPROTO;
+			}
+			return layr->dn->transmit(layr->dn, &info, pkt);
+		}
+	case CAIF_MODEMCMD_FLOW_OFF_REQ:
+		{
+			cfpkt_t *pkt;
+			transmt_info info;
+			uint8 flow_off = SRVL_FLOW_OFF;
+			memset(&info, 0, sizeof(info));
+			info.channel_id = service->layer.id;
+			info.phid = service->phid;
+			info.hdr_len = 1;
+			CFLOG_TRACE(("cfsrvl: ctrlcmd SEND_FLOW_OFF\n"));
+			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+			if (!cfpkt_add_head(pkt, &flow_off, 1)) {
+				CFLOG_ERROR(("cfsrvl: Packet is erroneous!\n"));
+				cfpkt_destroy(pkt);
+				return CFGLU_EPROTO;
+			}
+			return layr->dn->transmit(layr->dn, &info, pkt);
+		}
+	default:
+	  break;
+	}
+	return CFGLU_EINVAL;
+}
+
+void cfservl_destroy(layer_t *layer)
+{
+	cfglu_free(layer);
+}
+
+void cfsrvl_init(cfsrvl_t *service, uint8 channel_id, uint8 phyid)
+{
+	cfsrvl_t *srvl = cfglu_alloc(sizeof(cfsrvl_t));
+	cfglu_assert(offsetof(cfsrvl_t, layer) == 0);
+	memset(srvl, 0, sizeof(cfsrvl_t));
+	service->open = false;
+	service->modem_flow_on = true;
+	service->phy_flow_on = true;
+	service->layer.id = channel_id;
+	service->phid = phyid;
+	service->layer.ctrlcmd = cfservl_ctrlcmd;
+	service->layer.modemcmd = cfservl_modemcmd;
+}
+
+bool cfsrvl_ready(cfsrvl_t *service, int *err)
+{
+	if (service->open && service->modem_flow_on && service->phy_flow_on)
+		return true;
+	if (!service->open) {
+		*err = CFGLU_ENOTCONN;
+		return false;
+	}
+	cfglu_assert(!(service->modem_flow_on && service->phy_flow_on));
+	*err = CFGLU_ERETRY;
+	return false;
+}
+uint8 cfsrvl_getphyid(layer_t *layer)
+{
+	cfsrvl_t *servl = container_obj(layer);
+	return servl->phid;
+}
+
+bool cfsrvl_phyid_match(layer_t *layer, int phyid)
+{
+	cfsrvl_t *servl = container_obj(layer);
+	return servl->phid == phyid;
+}
diff --git a/net/caif/generic/cfutill.c b/net/caif/generic/cfutill.c
new file mode 100644
index 0000000..332a7ce
--- /dev/null
+++ b/net/caif/generic/cfutill.c
@@ -0,0 +1,115 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+#define container_obj(layr) ((cfsrvl_t *) layr)
+#define UTIL_PAYLOAD  0x00
+#define UTIL_CMD_BIT  0x80
+#define UTIL_REMOTE_SHUTDOWN 0x82
+#define UTIL_FLOW_OFF 0x81
+#define UTIL_FLOW_ON  0x80
+#define UTIL_CTRL_PKT_SIZE 1
+static int cfutill_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfutill_transmit(layer_t *layr, transmt_info *dummy,
+			    cfpkt_t *pkt);
+
+layer_t *cfutill_create(uint8 channel_id, uint8 phyid)
+{
+	cfsrvl_t *util = cfglu_alloc(sizeof(cfsrvl_t));
+	cfglu_assert(offsetof(cfsrvl_t, layer) == 0);
+
+	memset(util, 0, sizeof(cfsrvl_t));
+	cfsrvl_init(util, channel_id, phyid);
+	util->layer.receive = cfutill_receive;
+	util->layer.transmit = cfutill_transmit;
+	sprintf(util->layer.name, "util1");
+	return &util->layer;
+}
+
+
+
+static int cfutill_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	uint8 cmd = -1;
+	cfsrvl_t *service = container_obj(layr);
+	cfglu_assert(layr != NULL);
+	cfglu_assert(layr->up != NULL);
+	cfglu_assert(layr->up->receive != NULL);
+	cfglu_assert(layr->up->ctrlcmd != NULL);
+	if (!cfpkt_extr_head(pkt, &cmd, 1)) {
+		CFLOG_ERROR(("cfutill: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPROTO;
+	}
+
+	switch (cmd) {
+	case UTIL_PAYLOAD:
+		return layr->up->receive(layr->up, pkt);
+
+	case UTIL_FLOW_OFF:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+		cfpkt_destroy(pkt);
+		return 0;
+	case UTIL_FLOW_ON:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+		cfpkt_destroy(pkt);
+		return 0;
+	case UTIL_REMOTE_SHUTDOWN:	/* Remote Shutdown Request */
+		CFLOG_ERROR(("cfutill: REMOTE SHUTDOWN REQUEST RECEIVED\n"));
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
+		service->open = false;
+		cfpkt_destroy(pkt);
+		return 0;
+	default:
+		cfpkt_destroy(pkt);
+		CFLOG_ERROR(("cfmuxl: Unknown datagram control %d (0x%x!\n",
+			     cmd, cmd));
+		return CFGLU_EPROTO;
+	}
+}
+
+static int cfutill_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt)
+{
+	uint8 zero = 0;
+	transmt_info info;
+	int ret;
+	cfsrvl_t *service = container_obj(layr);
+	cfglu_assert(layr != NULL);
+	cfglu_assert(layr->dn != NULL);
+	cfglu_assert(layr->dn->transmit != NULL);
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+
+	if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("packet too large size=%d\n", cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+
+	cfpkt_add_head(pkt, &zero, 1);
+	memset(&info, 0, sizeof(info));
+	/* Add info for MUX-layer to route the packet out */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	/* For optimizing alignment we add up the size of CAIF header before
+	   payload */
+	info.hdr_len = 1;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0) {
+		uint32 tmp32;
+		cfpkt_extr_head(pkt, &tmp32, 4);
+	}
+	return ret;
+}
diff --git a/net/caif/generic/cfveil.c b/net/caif/generic/cfveil.c
new file mode 100644
index 0000000..0be7018
--- /dev/null
+++ b/net/caif/generic/cfveil.c
@@ -0,0 +1,118 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+
+
+#define VEI_PAYLOAD  0x00
+#define VEI_CMD_BIT  0x80
+#define VEI_FLOW_OFF 0x81
+#define VEI_FLOW_ON  0x80
+#define VEI_SET_PIN  0x82
+#define VEI_CTRL_PKT_SIZE 1
+#define container_obj(layr) cfglu_container_of(layr, cfsrvl_t, layer)
+
+static int cfvei_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfvei_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt);
+
+layer_t *cfvei_create(uint8 channel_id, uint8 phyid)
+{
+	cfsrvl_t *vei = cfglu_alloc(sizeof(cfsrvl_t));
+	cfglu_assert(offsetof(cfsrvl_t, layer) == 0);
+	memset(vei, 0, sizeof(cfsrvl_t));
+	cfsrvl_init(vei, channel_id, phyid);
+	vei->layer.receive = cfvei_receive;
+	vei->layer.transmit = cfvei_transmit;
+	sprintf(vei->layer.name, "vei%d", channel_id);
+	CFLOG_TRACE(("cfvei: Created %p\n", (void *) vei));
+	return &vei->layer;
+}
+
+
+
+static int cfvei_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	uint8 cmd;
+	int ret;
+	CFLOG_ENTER(("\n"));
+	cfglu_assert(layr->up != NULL);
+	cfglu_assert(layr->receive != NULL);
+	cfglu_assert(layr->ctrlcmd != NULL);
+
+
+	if (!cfpkt_extr_head(pkt, &cmd, 1)) {
+		CFLOG_ERROR(("cfvei: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		CFLOG_ENTER(("\n"));
+		return CFGLU_EPROTO;
+	}
+	switch (cmd) {
+	case VEI_PAYLOAD:
+		ret = layr->up->receive(layr->up, pkt);
+		CFLOG_EXIT(("\n"));
+		return ret;
+	case VEI_FLOW_OFF:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EOK;
+	case VEI_FLOW_ON:
+		layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EOK;
+	case VEI_SET_PIN:	/* SET RS232 PIN */
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("\n"));
+		return CFGLU_EOK;
+	default:		/* SET RS232 PIN */
+		CFLOG_ERROR(("cfvei: Unknown VEI Control packet %d (0x%x)!\n",
+			     cmd, cmd));
+		cfpkt_destroy(pkt);
+		CFLOG_EXIT(("error"));
+		return CFGLU_EPROTO;
+	}
+}
+
+static int cfvei_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt)
+{
+	uint8 tmp = 0;
+	transmt_info info;
+	int ret;
+	cfsrvl_t *service = container_obj(layr);
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+
+	cfglu_assert(layr->dn != NULL);
+	cfglu_assert(layr->dn->transmit != NULL);
+	if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+		CFLOG_ERROR(("packert too large size=%d\n",
+			     cfpkt_getlen(pkt)));
+		return CFGLU_EOVERFLOW;
+	}
+
+	if (!cfpkt_add_head(pkt, &tmp, 1)) {
+		CFLOG_ERROR(("cfvei: Packet is erroneous!\n"));
+		return CFGLU_EPKT;
+	}
+
+	/* Add info for MUX-layer to route the packet out */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+	info.hdr_len = 1;
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_extr_head(pkt, &tmp, 1);
+	return ret;
+}
diff --git a/net/caif/generic/cfvidl.c b/net/caif/generic/cfvidl.c
new file mode 100644
index 0000000..9200450
--- /dev/null
+++ b/net/caif/generic/cfvidl.c
@@ -0,0 +1,68 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+
+
+
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfsrvl.h>
+#include <net/caif/generic/cfpkt.h>
+#define container_obj(layr) ((cfsrvl_t *) layr)
+
+
+static int cfvidl_receive(layer_t *layr, cfpkt_t *pkt);
+static int cfvidl_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt);
+
+layer_t *cfvidl_create(uint8 channel_id, uint8 phyid)
+{
+	cfsrvl_t *vid = cfglu_alloc(sizeof(cfsrvl_t));
+	cfglu_assert(offsetof(cfsrvl_t, layer) == 0);
+
+	memset(vid, 0, sizeof(cfsrvl_t));
+	cfsrvl_init(vid, channel_id, phyid);
+	vid->layer.receive = cfvidl_receive;
+	vid->layer.transmit = cfvidl_transmit;
+	sprintf(vid->layer.name, "vid1");
+	return &vid->layer;
+}
+
+static int cfvidl_receive(layer_t *layr, cfpkt_t *pkt)
+{
+	uint32 videoheader;
+	if (!cfpkt_extr_head(pkt, &videoheader, 4)) {
+		CFLOG_ERROR(("cfvidl: Packet is erroneous!\n"));
+		cfpkt_destroy(pkt);
+		return CFGLU_EPROTO;
+	}
+	return layr->up->receive(layr->up, pkt);
+}
+
+static int cfvidl_transmit(layer_t *layr, transmt_info *dummy, cfpkt_t *pkt)
+{
+	cfsrvl_t *service = container_obj(layr);
+	uint32 videoheader = 0;
+	int ret;
+	transmt_info info;
+	if (!cfsrvl_ready(service, &ret))
+		return ret;
+	cfpkt_add_head(pkt, &videoheader, 4);
+	memset(&info, 0, sizeof(info));
+	/* Add info for MUX-layer to route the packet out */
+	info.channel_id = service->layer.id;
+	info.phid = service->phid;
+
+	ret = layr->dn->transmit(layr->dn, &info, pkt);
+	if (ret < 0)
+		cfpkt_extr_head(pkt, &videoheader, 4);
+	return ret;
+}
diff --git a/net/caif/generic/fcs.c b/net/caif/generic/fcs.c
new file mode 100644
index 0000000..7258321
--- /dev/null
+++ b/net/caif/generic/fcs.c
@@ -0,0 +1,58 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+/* NOTE: Move this to glue and use OS specific function if exists */
+
+#include <net/caif/generic/cfglue.h>
+
+static uint16 fcstab[256] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+
+uint16 fcs16(uint16 fcs, uint8 *cp, uint16 len)
+{
+	while (len--)
+		fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+	return fcs;
+}
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 5/8-v2] CAIF Protocol Stack
  2009-10-09 13:39       ` [PATCH] [CAIF-RFC 4/8-v2] " sjur.brandeland
@ 2009-10-09 13:39         ` sjur.brandeland
  2009-10-09 13:39           ` [PATCH] [CAIF-RFC 6/8-v2] " sjur.brandeland
                             ` (2 more replies)
  2009-10-12 12:20         ` [PATCH] [CAIF-RFC 4/8-v2] " Stefano Babic
  1 sibling, 3 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: I205c5b3baf1542e1593637ce896d8684870415be
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 net/caif/Kconfig            |   61 ++
 net/caif/Makefile           |   56 ++
 net/caif/caif_chnlif.c      |  219 +++++++
 net/caif/caif_chr.c         |  374 ++++++++++++
 net/caif/caif_config_util.c |  167 ++++++
 net/caif/chnl_chr.c         | 1393 +++++++++++++++++++++++++++++++++++++++++++
 net/caif/chnl_net.c         |  492 +++++++++++++++
 7 files changed, 2762 insertions(+), 0 deletions(-)
 create mode 100644 net/caif/Kconfig
 create mode 100644 net/caif/Makefile
 create mode 100644 net/caif/caif_chnlif.c
 create mode 100644 net/caif/caif_chr.c
 create mode 100644 net/caif/caif_config_util.c
 create mode 100644 net/caif/chnl_chr.c
 create mode 100644 net/caif/chnl_net.c

diff --git a/net/caif/Kconfig b/net/caif/Kconfig
new file mode 100644
index 0000000..7fb9e9c
--- /dev/null
+++ b/net/caif/Kconfig
@@ -0,0 +1,61 @@
+#
+# CAIF net configurations
+#
+
+#menu "Caif Support"
+comment "CAIF Support"
+
+menuconfig CAIF
+	tristate "Enable Caif support"
+	default n
+	---help---
+	Say Y here if you need to use a phone modem that uses CAIF as transport
+	You will also need to say yes to any caif physical devices that your platform
+	supports.
+	This can be either built-in or as a loadable module, if you select to build it as module
+	the other CAIF also needs to built as modules
+	See Documentation/CAIF for a further explanation on how to use and configure.
+
+if CAIF
+
+config CAIF_CHARDEV
+	tristate "CAIF character device"
+	default CAIF
+	---help---
+	Say Y if you will be using the CAIF AT type character devices.
+	This can be either built-in or as a loadable module,
+	If you select to build it as a built in then the main caif device must also be a builtin.
+	If unsure say Y.
+
+config CAIF_NETDEV
+	tristate "CAIF Network device"
+	default CAIF
+	---help---
+	Say Y if you will be using the CAIF based network device.
+	This can be either built-in or as a loadable module,
+	If you select to build it as a built in then the main caif device must also be a builtin.
+	If unsure say Y.
+
+
+config  CAIF_USE_PLAIN
+	bool  "Use plain buffers instead of SKB in caif"
+	default n
+	---help---
+	Use plain buffer to transport data,
+	Select what type of internal buffering CAIF should use,
+	skb or plain.
+	If unsure say N hre.
+
+config  CAIF_DEBUG
+	bool "Enable Debug"
+	default n
+	--- help ---
+	Enable the inclusion of debug code in the caif stack,
+	be aware that doing this will impact performance.
+	If unsure say N here.
+
+# Include physical drivers
+# source "drivers/net/caif/Kconfig"
+source "drivers/net/caif/Kconfig"
+endif
+#endmenu
diff --git a/net/caif/Makefile b/net/caif/Makefile
new file mode 100644
index 0000000..d98bc0a
--- /dev/null
+++ b/net/caif/Makefile
@@ -0,0 +1,56 @@
+ifeq ($(CONFIG_CAIF_USE_PLAIN),1)
+CFPKT:=plain
+else
+CFPKT:=skbuff
+CAIF_FLAGS+=-DCAIF_USE_SKB
+endif
+
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_FLAGS+=-DCAIF_DEBUG_ON
+endif
+
+
+ccflags-y := $(CAIF_FLAGS)
+
+
+caif-objs :=  caif_chr.o caif_chnlif.o  caif_config_util.o \
+	generic/cfcnfg.o generic/cfmuxl.o generic/cfctrl.o \
+	generic/cffrml.o generic/cfveil.o generic/cflist.o  \
+	generic/fcs.o    generic/cfserl.o generic/cfdgml.o \
+	generic/cfspil.o generic/cfrfml.o generic/cfvidl.o \
+	generic/cfmsll.o generic/cfutill.o  generic/cfshml.o \
+	generic/cfloopcfg.o  generic/cflooplayer.o generic/cfsrvl.o \
+	generic/cfpkt_$(CFPKT).o
+
+
+clean-dirs:= .tmp_versions
+
+clean-files:= Module.symvers modules.order *.cmd *~ \
+	generic/loopback/Module.symvers \
+	generic/loopback/modules.order \
+	generic/loopback/*.cmd \
+	generic/loopback/*.o \
+	generic/loopback/*~ \
+	generic/Module.symvers \
+	generic/modules.order \
+	generic/*.cmd \
+	generic/*.o \
+	generic/*~
+
+
+# Main caif module
+obj-$(CONFIG_CAIF) += caif.o
+
+# Character device
+obj-$(CONFIG_CAIF_CHARDEV) += chnl_chr.o
+
+# Net device
+obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
+
+export-objs := caif_chr.o
+
+clean:
+	${MAKE} -C generic clean
+	rm generic/modules.order  generic/Module.symvers generic/*.cmd generic/*~ \
+	generic/modules.order generic/Module.symvers \
+	generic/*.o generic/loopback/*.o
diff --git a/net/caif/caif_chnlif.c b/net/caif/caif_chnlif.c
new file mode 100644
index 0000000..896938f
--- /dev/null
+++ b/net/caif/caif_chnlif.c
@@ -0,0 +1,219 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2.
+*
+*/
+
+#include <linux/skbuff.h>
+#include <net/caif/caif_kernel.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/caif_config_util.h>
+#include <net/caif/caif_log.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfglue.h>
+
+
+
+struct caif_kernelif {
+	layer_t layer;
+	struct caif_device *dev;
+	cfctrl_link_param_t param;
+};
+static cfcnfg_t *cnfg;
+/**
+ * func chnlif_set_cnfg - Set the global config
+ * @cfg:	Config structure to set
+*/
+
+void chnlif_set_cnfg(cfcnfg_t *cfg)
+{
+	cnfg = cfg;
+}
+EXPORT_SYMBOL(chnlif_set_cnfg);
+
+/**
+ * func caif_create_skb - Creates a caif skb buffer
+ * @data:	data to add to buffer
+ * @data_length: lenht of data
+*/
+struct sk_buff *caif_create_skb(unsigned char *data, unsigned int data_length)
+{
+	/* NOTE: Make room for CAIF headers when using SKB inside CAIF. */
+	struct sk_buff *skb =
+	    alloc_skb(data_length + CAIF_SKB_HEAD_RESERVE +
+		      CAIF_SKB_TAIL_RESERVE, GFP_ATOMIC);
+	skb_reserve(skb, CAIF_SKB_HEAD_RESERVE);
+	if (skb == NULL)
+		return NULL;
+
+	memcpy(skb_put(skb, data_length), data, data_length);
+	return skb;
+}
+EXPORT_SYMBOL(caif_create_skb);
+
+int
+caif_extract_and_destroy_skb(struct sk_buff *skb, unsigned char *data,
+			     unsigned int max_length)
+{
+	unsigned int len;
+	len = skb->len;
+	skb_linearize(skb);
+	if (skb->len > max_length)
+		return CFGLU_EOVERFLOW;
+	memcpy(data, skb->data, skb->len);
+	kfree_skb(skb);
+	return len;
+}
+EXPORT_SYMBOL(caif_extract_and_destroy_skb);
+
+/* NOTE: transmit takes ownership of the SKB.
+ *       i.e. transmit only fails on severe errors.
+ *       flow_off is not checked on transmit this is clients responcibility.
+ */
+
+int caif_transmit(struct caif_device *dev, struct sk_buff *skb)
+{
+	struct caif_kernelif *chnlif =
+	    (struct caif_kernelif *) dev->_caif_handle;
+	cfpkt_t *pkt;
+#ifdef CAIF_USE_SKB
+	pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
+#else
+	pkt = cfpkt_create(skb->len);
+	cfpkt_add_body(pkt, skb->data, skb->len);
+	kfree_skb(skb);
+#endif
+	CAIFLOG_TRACE2("Transmit (%p)", chnlif->layer.dn);
+	return chnlif->layer.dn->transmit(chnlif->layer.dn, NULL, pkt);
+}
+EXPORT_SYMBOL(caif_transmit);
+
+
+int caif_flow_control(struct caif_device *dev, enum caif_flowctrl flow)
+{
+	caif_modemcmd_t modemcmd;
+	struct caif_kernelif *chnlif =
+	    (struct caif_kernelif *) dev->_caif_handle;
+	switch (flow) {
+	case CAIF_FLOWCTRL_ON:
+		modemcmd = CAIF_MODEMCMD_FLOW_ON_REQ;
+		break;
+	case CAIF_FLOWCTRL_OFF:
+		modemcmd = CAIF_MODEMCMD_FLOW_OFF_REQ;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return chnlif->layer.dn->modemcmd(chnlif->layer.dn, modemcmd);
+}
+EXPORT_SYMBOL(caif_flow_control);
+
+
+static int chnlif_receive(layer_t *layr, struct _cfpkt_t *cfpkt)
+{
+	/* FIXME: Use container of */
+	struct caif_kernelif *chnl = (struct caif_kernelif *) layr;
+
+	struct sk_buff *skb;
+#ifndef CAIF_USE_SKB
+	unsigned int pktlen = cfpkt_getlen(cfpkt);
+	unsigned int actual_len;
+	skb = alloc_skb(pktlen, GFP_ATOMIC);
+	if (skb == NULL)
+		return CFGLU_ENOMEM;
+
+	/* Extract data from the caif packet and copy it to the skb. */
+	cfpkt_extract(cfpkt, skb_put(skb, pktlen), pktlen, &actual_len);
+	cfglu_assert(pktlen == actual_len);
+	cfpkt_destroy(cfpkt);
+#else
+	skb = (struct sk_buff *) cfpkt_tonative(cfpkt);
+#endif
+	chnl->dev->receive_cb(chnl->dev, skb);
+	return CFGLU_EOK;
+}
+
+static void chnlif_flowctrl(layer_t *layr, caif_ctrlcmd_t ctrl, int phyid)
+{
+	struct caif_kernelif *chnl = (struct caif_kernelif *) layr;
+	enum caif_control ctl;
+
+	CAIFLOG_TRACE("Flow Control received %d\n", ctrl);
+
+	switch (ctrl) {
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+		ctl = CAIF_CONTROL_FLOW_OFF;
+		break;
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+		ctl = CAIF_CONTROL_FLOW_ON;
+		break;
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		ctl = CAIF_CONTROL_REMOTE_SHUTDOWN;
+		break;
+	case CAIF_CTRLCMD_DEINIT_RSP:
+		ctl = CAIF_CONTROL_DEV_DEINIT;
+		chnl->dev->_caif_handle = NULL;
+		chnl->dev->control_cb(chnl->dev, ctl);
+		memset(chnl, 0, sizeof(chnl));
+		cfglu_free(chnl);
+		return;
+
+	case CAIF_CTRLCMD_INIT_RSP:
+		ctl = CAIF_CONTROL_DEV_INIT;
+		break;
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+		ctl = CAIF_CONTROL_DEV_INIT_FAILED;
+		break;
+	default:
+		return;
+	}
+	chnl->dev->control_cb(chnl->dev, ctl);
+}
+
+
+int caif_add_device(struct caif_device *dev)
+{
+	int ret;
+	struct caif_kernelif *chnl = cfglu_alloc(sizeof(struct caif_kernelif));
+	chnl->dev = dev;
+	chnl->layer.ctrlcmd = chnlif_flowctrl;
+	chnl->layer.receive = chnlif_receive;
+	ret =
+	    channel_config_2_link_param(cnfg, &dev->caif_config, &chnl->param);
+
+
+	if (ret < 0) {
+		CAIFLOG_WARN("Bad Channel Configuration\n");
+		ret = CFGLU_EBADPARAM;
+		goto error;
+	}
+
+	if (!cfcnfg_add_adaptation_layer(cnfg, &chnl->param, &chnl->layer)) {
+		ret = CFGLU_ENOTCONN;
+		goto error;
+	}
+
+	dev->_caif_handle = chnl;
+
+	return CFGLU_EOK;
+error:
+	chnl->dev->_caif_handle = NULL;
+	memset(chnl, 0, sizeof(chnl));
+	cfglu_free(chnl);
+	return ret;
+}
+EXPORT_SYMBOL(caif_add_device);
+
+int caif_remove_device(struct caif_device *caif_dev)
+{
+
+	struct caif_kernelif *chnl =
+	    container_of(caif_dev->_caif_handle, struct caif_kernelif, layer);
+	bool ok = cfcnfg_del_adapt_layer(cnfg, &chnl->layer);
+	return ok ? CFGLU_EOK : CFGLU_EIO;
+}
+EXPORT_SYMBOL(caif_remove_device);
diff --git a/net/caif/caif_chr.c b/net/caif/caif_chr.c
new file mode 100644
index 0000000..e3e961f
--- /dev/null
+++ b/net/caif/caif_chr.c
@@ -0,0 +1,374 @@
+/*
+*      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/device.h>
+#include <linux/miscdevice.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <net/caif/caif_actions.h>
+#include <net/caif/caif_chr.h>
+#include <net/caif/generic/cfloopcfg.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/caif_config_util.h>
+#include <net/caif/caif_log.h>
+#include <linux/caif/caif_ioctl.h>
+
+#define caif_assert(assert) BUG_ON(!(assert))
+
+MODULE_LICENSE("GPL");
+static int (*chrdev_mgmt_func) (int action, union caif_action *param);
+static int (*netdev_mgmt_func) (int action, union caif_action *param);
+
+struct caif_chr {
+	cfcnfg_t *cfg;
+	cfloopcfg_t *loop;
+	struct miscdevice misc;
+};
+
+int caif_dbg_level = CAIFLOG_LEVEL_WARNING;
+EXPORT_SYMBOL(caif_dbg_level);
+
+static struct caif_chr caifdev;
+
+struct class caif_class = {
+	.name = "caif",
+};
+
+static ssize_t dbg_lvl_show(struct class *class, char *buf)
+{
+	return sprintf(buf, "%d\n", caif_dbg_level);
+}
+
+static ssize_t dbg_lvl_store(struct class *class, const char *buf,
+			     size_t count)
+{
+	int val;
+
+	sscanf(buf, "%d", &val);
+	if ((val < CAIFLOG_MIN_LEVEL) || (val > CAIFLOG_MAX_LEVEL)) {
+		printk(KERN_WARNING "caif_dbg_level: Invalid value\n");
+		return -EINVAL;
+	}
+
+	caif_dbg_level = val;
+
+	return count;
+}
+
+CLASS_ATTR(dbg_lvl, 0644, dbg_lvl_show, dbg_lvl_store);
+
+int caifdev_open(struct inode *inode, struct file *filp)
+{
+	printk(KERN_WARNING "caifdev_open: Entered\n");
+	return 0;
+}
+
+int caifdev_release(struct inode *inode, struct file *filp)
+{
+	printk(KERN_WARNING "caifdev_release: Entered\n");
+	return 0;
+}
+
+static int caifdev_ioctl(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long argp)
+{
+	union caif_action param;
+	int ret;
+	int (*mgmt_func) (int action, union caif_action *param) = NULL;
+	int type;
+	int size;
+	int operation;
+	enum caif_dev_type devtype;
+
+	printk(KERN_WARNING "caifdev_ioctl: Entered\n");
+
+	if (argp == 0) {
+		printk(KERN_INFO "caifdev_ioctl: argument is null\n");
+		return -EINVAL;
+	}
+
+	type = _IOC_TYPE(cmd);
+	printk(KERN_INFO "caifdev_ioctl: type = %d\n", type);
+
+	if (type != CAIF_IOC_MAGIC) {
+		printk(KERN_INFO "caifdev_ioctl: unknown ioctl type\n");
+		return -EINVAL;
+	}
+
+	/* Check if command is valid before copying anything */
+	switch (cmd) {
+	case CAIF_IOC_CONFIG_DEVICE:
+	case CAIF_IOC_REMOVE_DEVICE:
+		break;
+	default:
+		printk(KERN_INFO "caifdev_ioctl: unknown ioctl command\n");
+		return -EINVAL;
+	}
+
+	size = _IOC_SIZE(cmd);
+	printk(KERN_INFO "caifdev_ioctl: size = %d\n", size);
+
+	if (copy_from_user(&param, (void *) argp, size)) {
+		printk(KERN_WARNING
+		       "caifdev_ioctl: copy_from_user returned non zero.\n");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+
+	case CAIF_IOC_CONFIG_DEVICE:
+
+		operation = CAIF_ACT_CREATE_DEVICE;
+		devtype = param.create_channel.name.devtype;
+		break;
+
+	case CAIF_IOC_REMOVE_DEVICE:
+
+		operation = CAIF_ACT_DELETE_DEVICE;
+		devtype = param.delete_channel.devtype;
+		break;
+
+	default:
+		printk(KERN_INFO
+		       "caifdev_ioctl: OTHER ACTIONS NOT YET IMPLEMENTED\n");
+		return -EINVAL;
+	}
+
+	if (devtype == CAIF_DEV_CHR) {
+		printk(KERN_INFO "caifdev_ioctl: device type CAIF_DEV_CHR\n");
+		mgmt_func = chrdev_mgmt_func;
+	} else if (devtype == CAIF_DEV_NET) {
+		printk(KERN_INFO "caifdev_ioctl: device type CAIF_DEV_NET\n");
+		mgmt_func = netdev_mgmt_func;
+	}
+
+	if (mgmt_func == NULL) {
+		printk(KERN_WARNING
+		       "caifdev_ioctl: DevType %s is not registered\n",
+		       devtype == CAIF_DEV_CHR ? "CHAR" :
+		       devtype == CAIF_DEV_NET ? "NET" : "UNKNOWN");
+		return -EINVAL;
+	}
+
+	ret = (*mgmt_func) (operation, &param);
+
+	if (ret < 0) {
+		printk(KERN_INFO
+		       "caifdev_ioctl: error performing device operation\n");
+		return ret;
+	}
+	if (copy_to_user((void *) argp, &param, size)) {
+		printk(KERN_WARNING
+		       "caifdev_ioctl: copy_to_user returned non zero.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+const struct file_operations caifdev_fops = {
+	.owner = THIS_MODULE,
+	.open = caifdev_open,
+	.ioctl = caifdev_ioctl,
+	.release = caifdev_release,
+};
+
+void __exit caifdev_exit_module(void)
+{
+	class_remove_file(&caif_class, &class_attr_dbg_lvl);
+	class_unregister(&caif_class);
+	misc_deregister(&caifdev.misc);
+}
+
+int __init caifdev_init_module(void)
+{
+	int result;
+	/* FIXME: Reverse the directon, rather make chnlif do a get! */
+	extern void chnlif_set_cnfg(cfcnfg_t *cfg);
+
+	caifdev.cfg = cfcnfg_create();
+	if (!caifdev.cfg) {
+		printk(KERN_WARNING "caifdev: err: can't create cfcnfg.\n");
+		goto err_cfcnfg_create_failed;
+	}
+
+	chnlif_set_cnfg(caifdev.cfg);
+
+	caifdev.misc.minor = MISC_DYNAMIC_MINOR;
+	/*FIXME: Rename device to "caifconfig" */
+	caifdev.misc.name = "caifconfig";
+	caifdev.misc.fops = &caifdev_fops;
+
+	result = misc_register(&caifdev.misc);
+
+	if (result < 0) {
+		printk(KERN_WARNING
+		       "caifdev: err: %d, can't register misc.\n", result);
+		goto err_misc_register_failed;
+	}
+
+	/* Register class for SYSFS. */
+	result = class_register(&caif_class);
+	if (unlikely(result)) {
+		printk(KERN_WARNING
+		       "caifdev: err: %d, can't create sysfs node.\n", result);
+		goto err_class_register_failed;
+	}
+
+	/* Create SYSFS nodes. */
+	result = class_create_file(&caif_class, &class_attr_dbg_lvl);
+	if (unlikely(result)) {
+		printk(KERN_WARNING
+		       "caifdev: err: %d, can't create sysfs node.\n", result);
+		goto err_sysfs_create_failed;
+	}
+
+	return result;
+
+err_sysfs_create_failed:
+	class_unregister(&caif_class);
+err_class_register_failed:
+	misc_deregister(&caifdev.misc);
+err_misc_register_failed:
+err_cfcnfg_create_failed:
+	return -ENODEV;
+}
+
+int caifdev_phy_register(layer_t *phyif, cfcnfg_phy_type_t phy_type,
+			 cfcnfg_phy_preference_t phy_pref)
+{
+	uint16 phyid;
+
+	/* Hook up the physical interface.
+	 * Right now we are not using the returned id. */
+	cfcnfg_add_phy_layer(caifdev.cfg, phy_type, phyif, &phyid, phy_pref);
+
+	printk(KERN_WARNING "caifdev_phy_register: phyif:%p phyid:%d == phyif->id:%d\n",
+	       (void *)phyif, phyid, phyif->id);
+	return 0;
+}
+EXPORT_SYMBOL(caifdev_phy_register);
+
+int caifdev_phy_unregister(layer_t *phyif)
+{
+	printk(KERN_WARNING "caifdev_phy_unregister: phy:%p id:%d\n",
+	       phyif, phyif->id);
+	cfcnfg_del_phy_layer(caifdev.cfg, phyif);
+	return 0;
+}
+EXPORT_SYMBOL(caifdev_phy_unregister);
+
+
+int caifdev_phy_loop_register(layer_t *phyif, cfcnfg_phy_type_t phy_type)
+{
+	/* Create the loop stack. */
+	caifdev.loop = cfloopcfg_create();
+
+	/* Hook up the loop layer. */
+	cfloopcfg_add_phy_layer(caifdev.loop, phy_type, phyif);
+
+	return 0;
+}
+EXPORT_SYMBOL(caifdev_phy_loop_register);
+
+int caifdev_phy_spi_xmitlen(cfspil_t *layr)
+{
+	return cfspil_xmitlen(layr);
+}
+EXPORT_SYMBOL(caifdev_phy_spi_xmitlen);
+
+cfpkt_t *caifdev_phy_spi_getxmitpkt(cfspil_t *layr)
+{
+	return cfspil_getxmitpkt(layr);
+}
+EXPORT_SYMBOL(caifdev_phy_spi_getxmitpkt);
+
+/* FIXME: Generally comment on the new
+ *	   and old fashion functions for phy registration.
+ */
+
+int caifdev_adapt_register(struct caif_channel_config *config,
+			   layer_t *adap_layer)
+{
+	cfctrl_link_param_t param;
+
+	if (channel_config_2_link_param(caifdev.cfg, config, &param) == 0)
+		/* Hook up the adaptation layer. */
+		if (cfcnfg_add_adaptation_layer(caifdev.cfg,
+						&param, adap_layer))
+			return 0;
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(caifdev_adapt_register);
+
+
+/* FIXME: Comment on this function being new and not yet in use */
+int caifdev_adapt_unregister(layer_t *adap_layer)
+{
+	if (cfcnfg_del_adapt_layer(caifdev.cfg, adap_layer))
+		return 0;
+	else
+		return -1;
+}
+EXPORT_SYMBOL(caifdev_adapt_unregister);
+
+int caif_register_chrdev(int (*chrdev_mgmt)
+			  (int action, union caif_action *param))
+{
+
+	chrdev_mgmt_func = chrdev_mgmt;
+	return 0;
+}
+EXPORT_SYMBOL(caif_register_chrdev);
+
+int caif_register_netdev(int (*netdev_mgmt)
+			  (int action, union caif_action *param))
+{
+	netdev_mgmt_func = netdev_mgmt;
+	return 0;
+}
+EXPORT_SYMBOL(caif_register_netdev);
+
+
+void caif_unregister_chrdev()
+{
+	chrdev_mgmt_func = NULL;
+}
+EXPORT_SYMBOL(caif_unregister_chrdev);
+
+void caif_unregister_netdev()
+{
+	netdev_mgmt_func = NULL;
+}
+EXPORT_SYMBOL(caif_unregister_netdev);
+
+/* Exported CAIF functions. */
+EXPORT_SYMBOL(cfcnfg_get_packet_funcs);
+
+EXPORT_SYMBOL(serial_use_stx);
+
+extern cfglu_atomic_t cfpkt_packet_count;
+EXPORT_SYMBOL(cfpkt_packet_count);
+module_exit(caifdev_exit_module);
+subsys_initcall(caifdev_init_module);
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
new file mode 100644
index 0000000..d419b4e
--- /dev/null
+++ b/net/caif/caif_config_util.c
@@ -0,0 +1,167 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <net/caif/generic/cfglue.h>
+#include <net/caif/generic/cfctrl.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/caif_config_util.h>
+#include <linux/caif/caif_config.h>
+#include <linux/caif/caif_ioctl.h>
+#include <net/caif/caif_actions.h>
+
+
+
+int
+channel_config_2_link_param(cfcnfg_t *cnfg, struct caif_channel_config *s,
+			    cfctrl_link_param_t *l)
+{
+
+	cfcnfg_phy_preference_t pref;
+
+	memset(l, 0, sizeof(*l));
+
+	l->priority = s->priority;
+
+	if (s->phy_name[0] != '\0') {
+		l->phyid = cfcnfg_get_named(cnfg, s->phy_name);
+		CFLOG_TRACE(("PHYNAME: '%s' -> id:%d\n", s->phy_name,
+			     l->phyid));
+
+	} else {
+		switch (s->phy_pref) {
+		case CAIF_PHYPREF_UNSPECIFIED:
+			pref = CFPHYPREF_UNSPECIFIED;
+			break;
+		case CAIF_PHYPREF_LOW_LAT:
+			pref = CFPHYPREF_LOW_LAT;
+			break;
+		case CAIF_PHYPREF_HIGH_BW:
+			pref = CFPHYPREF_HIGH_BW;
+			break;
+		case _CAIF_PHYPREF_LOOP:
+			pref = CFPHYPREF_LOOP;
+			break;
+		case _CAIF_PHYPREF_RAW_LOOP:
+			pref = CFPHYPREF_RAW_LOOP;
+			break;
+		default:
+			CFLOG_TRACE(("PHYPREF: "
+				     "No Preferered Device Specified '%d'\n",
+				     s->phy_pref));
+			return -CFGLU_ENODEV;
+		}
+		l->phyid = cfcnfg_get_phyid(cnfg, pref);
+		CFLOG_TRACE(("PHYPREF: '%d' -> id:%d\n", pref, l->phyid));
+	}
+
+	switch (s->type) {
+	case CAIF_CHTY_AT:
+		l->linktype = CFCTRL_SRV_VEI;
+		l->chtype = 0x02;
+		l->endpoint = 0x00;
+		CFLOG_TRACE(("CHTY: AT\n"));
+		break;
+
+	case CAIF_CHTY_AT_CTRL:
+		CFLOG_TRACE(("CHTY: AT_CTRL\n"));
+		l->linktype = CFCTRL_SRV_VEI;
+		l->chtype = 0x00;
+		l->endpoint = 0x00;
+		break;
+
+	case CAIF_CHTY_AT_PAIRED:
+		CFLOG_TRACE(("CHTY: AT_PAIRED\n"));
+		l->linktype = CFCTRL_SRV_VEI;
+		l->chtype = 0x03;
+		l->endpoint = 0x00;
+		break;
+
+	case CAIF_CHTY_VIDEO:
+		CFLOG_TRACE(("CHTY: VIDEO\n"));
+		l->linktype = CFCTRL_SRV_VIDEO;
+		l->chtype = 0x00;
+		l->endpoint = 0x00;
+		l->u.video.connid = s->u.dgm.connection_id;
+		break;
+
+	case CAIF_CHTY_DATAGRAM:
+		CFLOG_TRACE(("CHTY: DATAGRAM\n"));
+		l->linktype = CFCTRL_SRV_DATAGRAM;
+		l->chtype = 0x00;
+		l->u.datagram.connid = s->u.dgm.connection_id;
+		break;
+
+	case CAIF_CHTY_DATAGRAM_LOOP:
+		CFLOG_TRACE(("CHTY: DATAGRAM\n"));
+		l->linktype = CFCTRL_SRV_DATAGRAM;
+		l->chtype = 0x03;
+		l->endpoint = 0x00;
+		l->u.datagram.connid = s->u.dgm.connection_id;
+		break;
+
+	case CAIF_CHTY_DEBUG:
+		CFLOG_TRACE(("CHTY: DEBUG\n"));
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = 0x01;	/* ACC SIDE */
+		l->chtype = 0x00;	/* Single channel with interactive
+					   debug and print-out mixed */
+		break;
+
+	case CAIF_CHTY_DEBUG_INTERACT:
+		CFLOG_TRACE(("CHTY: IDEBUG\n"));
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = 0x01;	/* ACC SIDE */
+		l->chtype = 0x02;	/* Interactive debug only */
+		break;
+
+	case CAIF_CHTY_DEBUG_TRACE:
+		CFLOG_TRACE(("CHTY: TRACE\n"));
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = 0x01;	/* ACC SIDE */
+		l->chtype = 0x01;	/* Debug print-out only */
+		break;
+
+	case CAIF_CHTY_RFM:
+
+		CFLOG_TRACE(("CHTY: RFN\n"));
+		l->linktype = CFCTRL_SRV_RFM;
+		l->u.datagram.connid = s->u.rfm.connection_id;
+		strncpy(l->u.rfm.volume, s->u.rfm.volume,
+			sizeof(l->u.rfm.volume));
+		break;
+
+	case CAIF_CHTY_UTILITY:
+		CFLOG_TRACE(("CHTY: UTILTY\n"));
+		l->linktype = CFCTRL_SRV_UTIL;
+		l->endpoint = 0x00;
+		l->chtype = 0x00;
+		l->u.utility.fifosize_bufs = s->u.utility.fifosize_bufs;
+		l->u.utility.fifosize_kb = s->u.utility.fifosize_kb;
+		strncpy(l->u.utility.name, s->u.utility.name,
+			sizeof(l->u.utility.name));
+		l->u.utility.paramlen = s->u.utility.paramlen;
+		if (l->u.utility.paramlen > sizeof(l->u.utility.params))
+			l->u.utility.paramlen = sizeof(l->u.utility.params);
+		memcpy(l->u.utility.params, s->u.utility.params,
+		       l->u.utility.paramlen);
+		break;
+
+	case CAIF_CHTY_RAW:
+		l->linktype = s->u._raw.channeltype;
+		l->endpoint = s->u._raw.endpoint;
+		l->chtype = s->u._raw.subtype;
+		break;
+
+	default:
+		CFLOG_TRACE(("CAIF_CHTY: Specified bad channel type '%d'\n",
+			     s->type));
+		return -CFGLU_EINVAL;
+	}
+	return 0;
+}
diff --git a/net/caif/chnl_chr.c b/net/caif/chnl_chr.c
new file mode 100644
index 0000000..28d269e
--- /dev/null
+++ b/net/caif/chnl_chr.c
@@ -0,0 +1,1393 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Per Sigmond / Per.Sigmond@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/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+/* Caif header files. */
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/generic/cffrml.h>
+#include <net/caif/caif_chr.h>
+#include <linux/caif/caif_config.h>
+#include <net/caif/caif_config_util.h>
+#include <net/caif/caif_actions.h>
+#include <net/caif/caif_log.h>
+MODULE_LICENSE("GPL");
+
+#define COUNTER_DEBUG 0
+
+#define CHNL_CHR_READ_QUEUE_HIGH 2000
+#define CHNL_CHR_READ_QUEUE_LOW 100
+
+static LIST_HEAD(caif_chrdev_list);
+static spinlock_t list_lock;
+
+#define CONN_STATE_OPEN_BIT           1
+#define CONN_STATE_PENDING_BIT        2
+
+#define TX_FLOW_ON_BIT                1
+#define RX_FLOW_ON_BIT                2
+
+#define STATE_IS_OPEN(dev) test_bit(CONN_STATE_OPEN_BIT,                \
+				    (void *) &(dev)->conn_state)
+#define STATE_IS_PENDING(dev) test_bit(CONN_STATE_PENDING_BIT,\
+				       (void *) &(dev)->conn_state)
+
+#define SET_STATE_OPEN(dev) set_bit(CONN_STATE_OPEN_BIT,\
+				    (void *) &(dev)->conn_state)
+#define SET_STATE_CLOSED(dev) clear_bit(CONN_STATE_OPEN_BIT,\
+					(void *) &(dev)->conn_state)
+#define SET_PENDING_ON(dev) set_bit(CONN_STATE_PENDING_BIT,\
+				    (void *) &(dev)->conn_state)
+#define SET_PENDING_OFF(dev) clear_bit(CONN_STATE_PENDING_BIT,\
+				       (void *) &(dev)->conn_state)
+
+#define RX_FLOW_IS_ON(dev) test_bit(RX_FLOW_ON_BIT,\
+				    (void *) &(dev)->flow_state)
+#define TX_FLOW_IS_ON(dev) test_bit(TX_FLOW_ON_BIT,\
+				    (void *) &(dev)->flow_state)
+
+#define SET_RX_FLOW_OFF(dev) clear_bit(RX_FLOW_ON_BIT,\
+				       (void *) &(dev)->flow_state)
+#define SET_RX_FLOW_ON(dev) set_bit(RX_FLOW_ON_BIT,\
+				    (void *) &(dev)->flow_state)
+#define SET_TX_FLOW_OFF(dev) clear_bit(TX_FLOW_ON_BIT,\
+				       (void *) &(dev)->flow_state)
+#define SET_TX_FLOW_ON(dev) set_bit(TX_FLOW_ON_BIT,\
+				    (void *) &(dev)->flow_state)
+
+#define CHR_READ_FLAG 0x01
+#define CHR_WRITE_FLAG 0x02
+
+#define chnl_assert(assert) BUG_ON(!(assert))
+
+#define CHNL_CHR_DEBUGFS
+#ifdef CHNL_CHR_DEBUGFS
+struct dentry *debugfsdir;
+#include <linux/debugfs.h>
+
+
+#endif
+
+
+struct caif_char_dev {
+	layer_t layer;
+	u32 conn_state;
+	u32 flow_state;
+	cfpktq_t *pktq;
+	char name[256];		/* Redundnt! Already in struct miscdevice */
+	struct miscdevice misc;
+	int file_mode;
+	caif_packet_funcs_t pktf;
+	struct caif_channel_config config;
+	/* Access to this struct and below layers */
+	struct mutex mutex;
+	int read_queue_len;
+	spinlock_t read_queue_len_lock;
+	wait_queue_head_t read_wq;
+	wait_queue_head_t mgmt_wq;
+	/* List of misc test devices */
+	struct list_head list_field;
+#ifdef CHNL_CHR_DEBUGFS
+	struct dentry *debugfs_device_dir;
+	atomic_t num_open;
+	atomic_t num_close;
+	atomic_t num_init;
+	atomic_t num_init_resp;
+	atomic_t num_init_fail_resp;
+	atomic_t num_deinit;
+	atomic_t num_deinit_resp;
+	atomic_t num_remote_shutdown_ind;
+	atomic_t num_tx_flow_off_ind;
+	atomic_t num_tx_flow_on_ind;
+	atomic_t num_rx_flow_off;
+	atomic_t num_rx_flow_on;
+#endif
+#if COUNTER_DEBUG
+	unsigned long counter;
+	int mismatch_reported;
+#endif
+
+};
+
+static void drain_queue(struct caif_char_dev *dev);
+
+
+/** Packet Receive Callback function called from CAIF Stack */
+
+static int caif_chrrecv_cb(layer_t *layr, cfpkt_t *pkt)
+{
+	struct caif_char_dev *dev;
+	int read_queue_high;
+#if COUNTER_DEBUG
+	unsigned long *data_p;
+#endif
+
+	CAIFLOG_ENTER("");
+	dev = container_of(layr, struct caif_char_dev, layer);
+
+	CAIFLOG_TRACE2("[%s] data received: %d bytes.\n",
+		       __func__, dev->pktf.cfpkt_getlen(pkt));
+
+	/** NOTE: This function may be called in Tasklet context! */
+
+
+
+#if COUNTER_DEBUG
+	dev->pktf.cfpkt_raw_extract(pkt, (void **) &data_p, 0);
+
+	if (data_p[0] == 1) {
+		dev->counter = data_p[0];
+		dev->mismatch_reported = 0;
+	}
+
+	if ((dev->counter != data_p[0]) && !dev->mismatch_reported) {
+		CAIFLOG_TRACE
+		    ("WARNING: caif_chrrecv_cb() - " "sequence: expected "
+		     "%ld, got %ld\n", dev->counter, data_p[0]);
+		dev->mismatch_reported = 1;
+	}
+
+	if (!(dev->counter % 100000))
+		CAIFLOG_TRACE("caif_chrrecv_cb(): %ld\n", dev->counter);
+
+
+	dev->counter++;
+#endif
+
+	/* The queue has its own lock */
+	dev->pktf.cfpkt_queue(dev->pktq, pkt, 0);
+	spin_lock(&dev->read_queue_len_lock);
+	dev->read_queue_len++;
+	read_queue_high = (dev->read_queue_len > CHNL_CHR_READ_QUEUE_HIGH);
+	spin_unlock(&dev->read_queue_len_lock);
+
+	if (RX_FLOW_IS_ON(dev) && read_queue_high) {
+
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_rx_flow_off);
+#endif
+
+		SET_RX_FLOW_OFF(dev);
+
+		/* Send flow off (NOTE: must not sleep) */
+		CAIFLOG_TRACE2
+		    ("caif_chrrecv_cb(): sending flow OFF (queue len = %d)\n",
+		     dev->read_queue_len);
+		chnl_assert(dev->layer.dn);
+		chnl_assert(dev->layer.dn->ctrlcmd);
+		(void) dev->layer.dn->modemcmd(dev->layer.dn,
+					       CAIF_MODEMCMD_FLOW_OFF_REQ);
+	}
+
+	/* Signal reader that data is available. */
+	wake_up_interruptible(&dev->read_wq);
+
+	return 0;
+}
+
+/** Packet Flow Control Callback function called from CAIF */
+static void caif_chrflowctrl_cb(layer_t *layr, caif_ctrlcmd_t flow, int phyid)
+{
+	struct caif_char_dev *dev;
+
+	CAIFLOG_ENTER("");
+
+	/** NOTE: This function may be called in Tasklet context! */
+	CAIFLOG_TRACE("AT flowctrl func called flow: %s.\n",
+		      flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
+		      flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
+		      flow == CAIF_CTRLCMD_INIT_RSP ? "INIT_RSP" :
+		      flow == CAIF_CTRLCMD_DEINIT_RSP ? "DEINIT_RSP" :
+		      flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "INIT_FAIL_RSP" :
+		      flow ==
+		      CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ? "REMOTE_SHUTDOWN" :
+		      "UKNOWN CTRL COMMAND");
+
+	dev = container_of(layr, struct caif_char_dev, layer);
+
+	switch (flow) {
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_FLOW_ON_IND\n",
+			      __func__, __LINE__);
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_tx_flow_on_ind);
+#endif
+		/* Signal reader that data is available. */
+		SET_TX_FLOW_ON(dev);
+		wake_up_interruptible(&dev->mgmt_wq);
+		break;
+
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_tx_flow_off_ind);
+#endif
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_FLOW_OFF_IND\n",
+			      __func__, __LINE__);
+		SET_TX_FLOW_OFF(dev);
+		break;
+
+	case CAIF_CTRLCMD_INIT_RSP:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_INIT_RSP\n",
+			      __func__, __LINE__);
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_init_resp);
+#endif
+		/* Signal reader that data is available. */
+		BUG_ON(!STATE_IS_OPEN(dev));
+		SET_PENDING_OFF(dev);
+		SET_TX_FLOW_ON(dev);
+		wake_up_interruptible(&dev->mgmt_wq);
+		break;
+
+	case CAIF_CTRLCMD_DEINIT_RSP:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_DEINIT_RSP\n",
+			      __func__, __LINE__);
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_deinit_resp);
+#endif
+		BUG_ON(STATE_IS_OPEN(dev));
+		SET_PENDING_OFF(dev);
+		wake_up_interruptible(&dev->mgmt_wq);
+		break;
+
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_INIT_FAIL_RSP\n",
+			      __func__, __LINE__);
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_init_fail_resp);
+#endif
+		BUG_ON(!STATE_IS_OPEN(dev));
+		SET_STATE_CLOSED(dev);
+		SET_PENDING_OFF(dev);
+		SET_TX_FLOW_OFF(dev);
+		wake_up_interruptible(&dev->mgmt_wq);
+		break;
+
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		CAIFLOG_TRACE("[%s:%d] CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND\n",
+			      __func__, __LINE__);
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_remote_shutdown_ind);
+#endif
+		BUG_ON(!STATE_IS_OPEN(dev));
+		BUG_ON(!STATE_IS_PENDING(dev));
+
+		SET_STATE_CLOSED(dev);
+		SET_TX_FLOW_OFF(dev);
+
+		drain_queue(dev);
+		SET_RX_FLOW_ON(dev);
+		dev->file_mode = 0;
+
+		wake_up_interruptible(&dev->mgmt_wq);
+		break;
+
+	default:
+		CAIFLOG_TRACE("[%s:%d] Unexpected flow command %d\n",
+			      __func__, __LINE__, flow);
+
+	}
+}
+
+/** Device Read function called from Linux Kernel */
+ssize_t caif_chrread(struct file *filp, char __user *buf, size_t count,
+		     loff_t *f_pos)
+{
+	cfpkt_t *pkt = NULL;
+	unsigned char *rxbuf = NULL;
+	size_t len;
+	int result;
+	struct caif_char_dev *dev = filp->private_data;
+	ssize_t ret = -EIO;
+	int read_queue_low;
+
+	CAIFLOG_ENTER("");
+
+	if (dev == NULL) {
+		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
+			      __func__, __LINE__);
+		return -EBADFD;
+	}
+
+
+	/* I want to be alone on dev (except status and queue) */
+	if (mutex_lock_interruptible(&dev->mutex)) {
+		CAIFLOG_TRACE
+		    ("caif_chrread: mutex_lock_interruptible got signalled\n");
+		return -ERESTARTSYS;
+	}
+
+	chnl_assert(dev->pktq);
+
+	if (!STATE_IS_OPEN(dev)) {
+		/* Device is closed or closing */
+		if (!STATE_IS_PENDING(dev)) {
+			CAIFLOG_TRACE("device is closed (by remote end)\n");
+			ret = -EPIPE;
+		} else {
+			CAIFLOG_TRACE("device is closing...\n");
+			ret = -EBADF;
+		}
+		goto read_error;
+	}
+
+	/* Device is open or opening */
+	if (STATE_IS_PENDING(dev)) {
+		CAIFLOG_TRACE("device is opening...\n");
+
+		if (filp->f_flags & O_NONBLOCK) {
+			/* We can't block */
+			CAIFLOG_TRACE("state pending and O_NONBLOCK\n");
+			ret = -EAGAIN;
+			goto read_error;
+		}
+
+		/* Blocking mode; state is pending and we need to wait
+		   for its conclusion */
+		result =
+		    wait_event_interruptible(dev->mgmt_wq,
+					     !STATE_IS_PENDING(dev));
+		if (result == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    (" wait_event_interruptible woken by a signal (1)");
+			ret = -ERESTARTSYS;
+			goto read_error;
+		}
+	}
+
+	/* Block if we don't have any received buffers. */
+	/* The queue has its own lock */
+	while ((pkt = dev->pktf.cfpkt_qpeek(dev->pktq)) == NULL) {
+
+		if (filp->f_flags & O_NONBLOCK) {
+			CAIFLOG_TRACE("caif_chrread: O_NONBLOCK\n");
+			ret = -EAGAIN;
+			goto read_error;
+		}
+		CAIFLOG_TRACE2("[%s:%d] wait_event\n", __func__, __LINE__);
+
+		/* Let writers in */
+		mutex_unlock(&dev->mutex);
+
+		/* Block reader until data arrives or device is closed. */
+		if (wait_event_interruptible(dev->read_wq,
+					     dev->pktf.cfpkt_qpeek(dev->pktq)
+					     || !STATE_IS_OPEN(dev)) ==
+		    -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    ("caif_chrread: wait_event_interruptible woken by "
+			     "a signal, signal_pending(current) = %d\n",
+			     signal_pending(current));
+			return -ERESTARTSYS;
+		}
+
+		CAIFLOG_TRACE2("[%s:%d] awake\n", __func__, __LINE__);
+
+		/* I want to be alone on dev (except status and queue) */
+		if (mutex_lock_interruptible(&dev->mutex)) {
+			CAIFLOG_TRACE
+			    ("caif_chrread: "
+			     "mutex_lock_interruptible got signalled\n");
+			return -ERESTARTSYS;
+		}
+
+		if (!STATE_IS_OPEN(dev)) {
+			/* someone closed the link, report error */
+			CAIFLOG_TRACE("[%s:%d] remote end shutdown!\n",
+				      __func__, __LINE__);
+			ret = -EPIPE;
+			goto read_error;
+		}
+
+	}
+
+	/* The queue has its own lock */
+	len = dev->pktf.cfpkt_getlen(pkt);
+
+	/* Check max length that can be copied. */
+	if (len > count) {
+		CAIFLOG_TRACE("caif_chrread: user buffer too small\n");
+		ret = -EINVAL;
+		goto read_error;
+	}
+
+	/* Get packet from queue */
+	/* The queue has its own lock */
+	pkt = dev->pktf.cfpkt_dequeue(dev->pktq);
+
+	spin_lock(&dev->read_queue_len_lock);
+	dev->read_queue_len--;
+	read_queue_low = (dev->read_queue_len < CHNL_CHR_READ_QUEUE_LOW);
+	spin_unlock(&dev->read_queue_len_lock);
+
+	if (!RX_FLOW_IS_ON(dev) && read_queue_low) {
+
+#ifdef CHNL_CHR_DEBUGFS
+		atomic_inc(&dev->num_rx_flow_on);
+#endif
+
+		SET_RX_FLOW_ON(dev);
+
+		/* Send flow on */
+		CAIFLOG_TRACE2
+		    ("caif_chrread(): sending flow ON (queue len = %d)\n",
+		     dev->read_queue_len);
+		chnl_assert(dev->layer.dn);
+		chnl_assert(dev->layer.dn->ctrlcmd);
+		(void) dev->layer.dn->modemcmd(dev->layer.dn,
+					       CAIF_MODEMCMD_FLOW_ON_REQ);
+
+		chnl_assert(dev->read_queue_len >= 0);
+
+	}
+
+	result = dev->pktf.cfpkt_raw_extract(pkt, (void **) &rxbuf, len);
+
+	chnl_assert(result >= 0);
+
+	if (result < 0) {
+		CAIFLOG_TRACE("caif_chrread: cfpkt_raw_extract failed\n");
+		dev->pktf.cfpkt_destroy(pkt);
+		ret = -EINVAL;
+		goto read_error;
+	}
+
+	/* Copy data from the RX buffer to the user buffer. */
+	if (copy_to_user(buf, rxbuf, len)) {
+		CAIFLOG_TRACE("caif_chrread: copy_to_user returned non zero.");
+		dev->pktf.cfpkt_destroy(pkt);
+		ret = -EINVAL;
+		goto read_error;
+	}
+
+
+	/* Liberate packet. */
+	dev->pktf.cfpkt_destroy(pkt);
+
+
+	/* Let the others in */
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_EXIT("");
+	return len;
+
+read_error:
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+/** Device write function called from Linux Kernel (misc device) */
+ssize_t caif_chrwrite(struct file *filp, const char __user *buf,
+		      size_t count, loff_t *f_pos)
+{
+	cfpkt_t *pkt = NULL;
+	struct caif_char_dev *dev = filp->private_data;
+	transmt_info info;
+	unsigned char *txbuf;
+	ssize_t ret = -EIO;
+	int result;
+	CAIFLOG_ENTER("");
+
+	if (dev == NULL) {
+		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
+			      __func__, __LINE__);
+		ret = -EBADFD;
+		goto write_error_no_unlock;
+	}
+
+
+	if (count > CAIF_MAX_PAYLOAD_SIZE) {
+		CAIFLOG_TRACE("[%s:%d] buffer too long\n", __func__, __LINE__);
+		ret = -EINVAL;
+		goto write_error_no_unlock;
+	}
+
+	/* I want to be alone on dev (except status and queue) */
+	if (mutex_lock_interruptible(&dev->mutex)) {
+		CAIFLOG_TRACE
+		    ("caif_chrwrite: mutex_lock_interruptible got signalled");
+		ret = -ERESTARTSYS;
+		goto write_error_no_unlock;
+	}
+
+	chnl_assert(dev->pktq);
+
+	if (!STATE_IS_OPEN(dev)) {
+		/* Device is closed or closing */
+		if (!STATE_IS_PENDING(dev)) {
+			CAIFLOG_TRACE("device is closed (by remote end)\n");
+			ret = -EPIPE;
+		} else {
+			CAIFLOG_TRACE("device is closing...\n");
+			ret = -EBADF;
+		}
+		goto write_error;
+	}
+
+	/* Device is open or opening */
+	if (STATE_IS_PENDING(dev)) {
+		CAIFLOG_TRACE("device is opening...\n");
+
+		if (filp->f_flags & O_NONBLOCK) {
+			/* We can't block */
+			CAIFLOG_TRACE("state pending and O_NONBLOCK\n");
+			ret = -EAGAIN;
+			goto write_error;
+		}
+
+		/* Blocking mode; state is pending and we need to wait
+		   for its conclusion */
+		result =
+		    wait_event_interruptible(dev->mgmt_wq,
+					     !STATE_IS_PENDING(dev));
+		if (result == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    (" wait_event_interruptible woken by a signal (1)");
+			ret = -ERESTARTSYS;
+			goto write_error;
+		}
+	}
+
+	if (!TX_FLOW_IS_ON(dev)) {
+
+		/* Flow is off. Check non-block flag */
+		if (filp->f_flags & O_NONBLOCK) {
+			CAIFLOG_TRACE
+			    ("caif_chrwrite: O_NONBLOCK and tx flow off");
+			ret = -EAGAIN;
+			goto write_error;
+		}
+
+		/* Let readers in */
+		mutex_unlock(&dev->mutex);
+
+		/* Wait until flow is on or device is closed */
+		if (wait_event_interruptible(dev->mgmt_wq, TX_FLOW_IS_ON(dev)
+					     || !STATE_IS_OPEN(dev)) ==
+		    -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    ("caif_chrwrite:"
+			     " wait_event_interruptible woken by a signal");
+			ret = -ERESTARTSYS;
+			goto write_error_no_unlock;
+		}
+
+		/* I want to be alone on dev (except status and queue) */
+		if (mutex_lock_interruptible(&dev->mutex)) {
+			CAIFLOG_TRACE
+			    ("mutex_lock_interruptible got signalled\n");
+			ret = -ERESTARTSYS;
+			goto write_error_no_unlock;
+		}
+
+		if (!STATE_IS_OPEN(dev)) {
+			/* someone closed the link, report error */
+			CAIFLOG_TRACE("[%s:%d] remote end shutdown!\n",
+				      __func__, __LINE__);
+			ret = -EPIPE;
+			goto write_error;
+		}
+	}
+
+	/* Create packet, buf=NULL means no copying */
+	pkt = dev->pktf.cfpkt_create_xmit_pkt((const unsigned char *) NULL,
+					      count);
+
+	if (pkt == NULL) {
+		CAIFLOG_TRACE
+		    ("caif_chrwrite: cfpkt_create_pkt returned NULL\n");
+		ret = -EIO;
+		goto write_error;
+	}
+
+	if (!dev->pktf.cfpkt_raw_append(pkt, (void **) &txbuf, count)) {
+		CAIFLOG_TRACE("caif_chrwrite: cfpkt_raw_append failed\n");
+		dev->pktf.cfpkt_destroy(pkt);
+		ret = -EINVAL;
+		goto write_error;
+	}
+
+	/* Copy data into buffer. */
+
+	if (copy_from_user(txbuf, buf, count)) {
+		CAIFLOG_TRACE
+		    ("caif_chrwrite: copy_from_user returned non zero.\n");
+		dev->pktf.cfpkt_destroy(pkt);
+		ret = -EINVAL;
+		goto write_error;
+	}
+
+	memset(&info, 0, sizeof(info));
+
+	/* Send the packet down the stack. */
+	chnl_assert(dev->layer.dn);
+	chnl_assert(dev->layer.dn->transmit);
+
+	do {
+		ret = dev->layer.dn->transmit(dev->layer.dn, &info, pkt);
+
+		if (likely(ret >= 0) || (ret != -EAGAIN))
+			break;
+
+		/* EAGAIN - retry */
+		if (filp->f_flags & O_NONBLOCK) {
+			CAIFLOG_TRACE
+			    ("NONBLOCK and transmit failed, error = %d\n",
+			     ret);
+			ret = -EAGAIN;
+			goto write_error;
+		}
+
+		/* Let readers in */
+		mutex_unlock(&dev->mutex);
+
+		/* Wait until flow is on or device is closed */
+		if (wait_event_interruptible(dev->mgmt_wq, TX_FLOW_IS_ON(dev)
+					     || !STATE_IS_OPEN(dev)) ==
+		    -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    ("wait_event_interruptible woken by a signal");
+			ret = -ERESTARTSYS;
+			goto write_error_no_unlock;
+		}
+
+		/* I want to be alone on dev (except status and queue) */
+		if (mutex_lock_interruptible(&dev->mutex)) {
+			CAIFLOG_TRACE
+			    ("mutex_lock_interruptible got signalled\n");
+			ret = -ERESTARTSYS;
+			goto write_error_no_unlock;
+		}
+
+	} while (ret == -EAGAIN);
+
+	if (ret < 0) {
+		dev->pktf.cfpkt_destroy(pkt);
+		CAIFLOG_TRACE("transmit failed, error = %d\n",
+			      ret);
+
+		goto write_error;
+	}
+
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_EXIT("");
+	return count;
+
+write_error:
+	mutex_unlock(&dev->mutex);
+write_error_no_unlock:
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+
+static unsigned int caif_chrpoll(struct file *filp, poll_table *waittab)
+{
+	struct caif_char_dev *dev = filp->private_data;
+	unsigned int mask = 0;
+
+	CAIFLOG_ENTER("");
+
+	if (dev == NULL) {
+		CAIFLOG_TRACE("[%s:%d] private_data not set!\n",
+			      __func__, __LINE__);
+		return -EBADFD;
+	}
+
+
+	/* I want to be alone on dev (except status and queue) */
+	if (mutex_lock_interruptible(&dev->mutex)) {
+		CAIFLOG_TRACE
+		    ("caif_chrpoll: mutex_lock_interruptible got signalled\n");
+		goto poll_error;
+	}
+
+	chnl_assert(dev->pktq);
+
+	if (!STATE_IS_OPEN(dev)) {
+		CAIFLOG_TRACE("[%s:%d] not open\n", __func__, __LINE__);
+		goto poll_error;
+	}
+
+	poll_wait(filp, &dev->read_wq, waittab);
+
+	if (dev->pktf.cfpkt_qpeek(dev->pktq) != NULL)
+		mask |= (POLLIN | POLLRDNORM);
+
+
+	if (TX_FLOW_IS_ON(dev))
+		mask |= (POLLOUT | POLLWRNORM);
+
+
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_TRACE("[%s:%d] caif_chrpoll mask=0x%04x...\n",
+		      __func__, __LINE__, mask);
+
+	CAIFLOG_EXIT("");
+	return mask;
+
+poll_error:
+	mask |= POLLERR;
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_EXIT("");
+	return mask;
+}
+
+/* Usage:
+   minor >= 0 : find from minor
+   minor < 0 and name == name : find from name
+   minor < 0 and name == NULL : get first
+*/
+
+static struct caif_char_dev *find_device(int minor, char *name,
+					 int remove_from_list)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct caif_char_dev *dev = NULL;
+	struct caif_char_dev *tmp;
+	CAIFLOG_ENTER("");
+	spin_lock(&list_lock);
+	CAIFLOG_TRACE("[%s:%d] start looping \n", __func__, __LINE__);
+	list_for_each_safe(list_node, n, &caif_chrdev_list) {
+		tmp = list_entry(list_node, struct caif_char_dev, list_field);
+		CAIFLOG_TRACE("[%s:%d] check %d,%d, %s, %s \n",
+			      __func__, __LINE__, tmp->misc.minor, minor,
+			      tmp->name, name);
+		if (minor >= 0) {	/* find from minor */
+			if (tmp->misc.minor == minor)
+				dev = tmp;
+
+		} else if (name) {	/* find from name */
+			if (!strncmp(tmp->name, name, sizeof(tmp->name)))
+				dev = tmp;
+		} else {	/* take first */
+			dev = tmp;
+		}
+
+		if (dev) {
+			CAIFLOG_TRACE("[%s:%d] match %d, %s \n",
+				      __func__, __LINE__, minor, name);
+			if (remove_from_list)
+				list_del(list_node);
+			break;
+		}
+	}
+	spin_unlock(&list_lock);
+	return dev;
+}
+
+#if CAIFLOG_ON
+static void print_device_list(void)
+{
+	int i = 0;
+	struct list_head *list_node;
+	struct caif_char_dev *tmp;
+	CAIFLOG_ENTER("");
+	spin_lock(&list_lock);
+	CAIFLOG_TRACE("List of devices:\n");
+	list_for_each(list_node, &caif_chrdev_list) {
+		tmp = list_entry(list_node, struct caif_char_dev, list_field);
+		CAIFLOG_TRACE("i = %d, minor= %d, name = %s, open = %d\n", i,
+			      tmp->misc.minor, tmp->name,
+			      STATE_IS_OPEN(tmp) ? 1 : 0);
+		i++;
+	}
+	if (i == 0)
+		CAIFLOG_TRACE("list is empty\n");
+
+	spin_unlock(&list_lock);
+}
+#endif
+
+
+static void drain_queue(struct caif_char_dev *dev)
+{
+	cfpkt_t *pkt;
+
+	/* Empty the queue */
+	do {
+		/* The queue has its own lock */
+		pkt = dev->pktf.cfpkt_dequeue(dev->pktq);
+
+		if (!pkt)
+			break;
+
+		CAIFLOG_TRACE
+		    ("[%s:%d] drain_queue(): freeing packet from read queue\n",
+		     __func__, __LINE__);
+		dev->pktf.cfpkt_destroy(pkt);
+
+	} while (1);
+
+	spin_lock(&dev->read_queue_len_lock);
+	dev->read_queue_len = 0;
+	spin_unlock(&dev->read_queue_len_lock);
+}
+
+
+int caif_chropen(struct inode *inode, struct file *filp)
+{
+	struct caif_char_dev *dev = NULL;
+	int result = -1;
+	int minor = iminor(inode);
+	int mode = 0;
+	int ret = -EIO;
+
+	CAIFLOG_ENTER("");
+
+	IF_CAIF_TRACE(print_device_list());
+
+	dev = find_device(minor, NULL, 0);
+
+	if (dev == NULL) {
+		CAIFLOG_TRACE("[%s] COULD NOT FIND DEVICE\n", __func__);
+		return -EBADF;
+	}
+
+	CAIFLOG_TRACE("dev=%p OPEN=%d, TX_FLOW=%d, RX_FLOW=%d\n", dev,
+		      STATE_IS_OPEN(dev),
+		      TX_FLOW_IS_ON(dev), RX_FLOW_IS_ON(dev));
+
+	CAIFLOG_TRACE("get mutex\n");
+
+	/* I want to be alone on dev (except status and queue) */
+	if (mutex_lock_interruptible(&dev->mutex)) {
+		CAIFLOG_TRACE
+		    ("caif_chropen: mutex_lock_interruptible got signalled\n");
+		return -ERESTARTSYS;
+	}
+#ifdef CHNL_CHR_DEBUGFS
+	atomic_inc(&dev->num_open);
+#endif
+	filp->private_data = dev;
+
+	switch (filp->f_flags & O_ACCMODE) {
+	case O_RDONLY:
+		mode = CHR_READ_FLAG;
+		break;
+	case O_WRONLY:
+		mode = CHR_WRITE_FLAG;
+		break;
+	case O_RDWR:
+		mode = CHR_READ_FLAG | CHR_WRITE_FLAG;
+		break;
+	}
+
+	/* If device is not open, make sure device is in fully closed state */
+	if (!STATE_IS_OPEN(dev)) {
+		/* Has link close response been received
+		   (if we ever sent it)? */
+		if (STATE_IS_PENDING(dev)) {
+			/* Still waiting for close response from remote.
+			   If opened non-blocking, report "would block" */
+			if (filp->f_flags & O_NONBLOCK) {
+				CAIFLOG_TRACE("O_NONBLOCK && close pending\n");
+				ret = -EAGAIN;
+				goto open_error;
+			}
+
+			CAIFLOG_TRACE
+			    ("wait for close response from remote...\n");
+
+			/* Blocking mode; close is pending and we need to wait
+			   for its conclusion */
+			result =
+			    wait_event_interruptible(dev->mgmt_wq,
+						     !STATE_IS_PENDING(dev));
+			if (result == -ERESTARTSYS) {
+				CAIFLOG_TRACE
+				    ("wait_event_interruptible woken"
+				     "by a signal (1)");
+				ret = -ERESTARTSYS;
+				goto open_error;
+			}
+		}
+	}
+
+	/* Device is now either closed, pending open or open */
+	if (STATE_IS_OPEN(dev) && !STATE_IS_PENDING(dev)) {
+		/* Open */
+		CAIFLOG_TRACE
+		    ("[%s:%d] Device is already opened (dev=%p) check access "
+		     "f_flags = 0x%x file_mode = 0x%x\n",
+		     __func__, __LINE__, dev, mode, dev->file_mode);
+
+		if (mode & dev->file_mode) {
+			CAIFLOG_TRACE
+			    ("[%s:%d] Access mode already in use 0x%x \n",
+			     __func__, __LINE__, mode);
+			ret = -EBUSY;
+			goto open_error;
+		}
+	} else {
+		/* We are closed or pending open.
+		 * If closed:       send link setup
+		 * If pending open: link setup already sent (we could have been
+		 *                  interrupted by a signal last time)
+		 */
+		if (!STATE_IS_OPEN(dev)) {
+			/* First opening of file; connect lower layers: */
+
+			dev->layer.receive = caif_chrrecv_cb;
+
+			SET_STATE_OPEN(dev);
+			SET_PENDING_ON(dev);
+
+			/* Register this channel. */
+			result =
+			    caifdev_adapt_register(&dev->config, &dev->layer);
+			if (result < 0) {
+				CAIFLOG_TRACE
+				    ("caif_chropen: can't register channel\n");
+				ret = -EIO;
+				SET_STATE_CLOSED(dev);
+				SET_PENDING_OFF(dev);
+				goto open_error;
+			}
+#ifdef CHNL_CHR_DEBUGFS
+			atomic_inc(&dev->num_init);
+#endif
+		}
+
+
+		/* If opened non-blocking, report "success".
+		 */
+		if (filp->f_flags & O_NONBLOCK) {
+			CAIFLOG_TRACE("caif_chropen: O_NONBLOCK success\n");
+			ret = 0;
+			goto open_success;
+		}
+
+		CAIFLOG_TRACE("WAIT FOR CONNECT RESPONSE \n");
+		result =
+		    wait_event_interruptible(dev->mgmt_wq,
+					     !STATE_IS_PENDING(dev));
+		if (result == -ERESTARTSYS) {
+			CAIFLOG_TRACE
+			    ("caif_chropen: "
+			     "wait_event_interruptible woken by a signal (2)");
+			ret = -ERESTARTSYS;
+			goto open_error;
+		}
+
+		if (!STATE_IS_OPEN(dev)) {
+			/* Lower layers said "no" */
+			CAIFLOG_TRACE
+			    ("[%s:%d] caif_chropen: CLOSED RECEIVED\n",
+			     __func__, __LINE__);
+			ret = -EPIPE;
+			goto open_error;
+		}
+
+		CAIFLOG_TRACE("[%s:%d] caif_chropen: CONNECT RECEIVED\n",
+			      __func__, __LINE__);
+	}
+open_success:
+	/* Open is ok */
+	dev->file_mode |= mode;
+
+	CAIFLOG_TRACE("[%s:%d] Open - file mode = %x\n",
+		      __func__, __LINE__, dev->file_mode);
+
+	CAIFLOG_TRACE("[%s:%d] CONNECTED \n", __func__, __LINE__);
+
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_EXIT("");
+	return 0;
+
+open_error:
+	mutex_unlock(&dev->mutex);
+	CAIFLOG_EXIT("");
+	return ret;
+}
+
+int caif_chrrelease(struct inode *inode, struct file *filp)
+{
+	struct caif_char_dev *dev = NULL;
+	int minor = iminor(inode);
+	int result;
+	int mode = 0;
+	int tx_flow_state_was_on;
+
+	CAIFLOG_ENTER("");
+
+	IF_CAIF_TRACE(print_device_list());
+	dev = find_device(minor, NULL, 0);
+	if (dev == NULL) {
+		CAIFLOG_TRACE("[%s] COULD NOT FIND DEVICE\n", __func__);
+		return -EBADF;
+	}
+
+	/* I want to be alone on dev (except status queue) */
+	if (mutex_lock_interruptible(&dev->mutex)) {
+		CAIFLOG_TRACE
+		    ("caif_chrrelease: "
+		     "mutex_lock_interruptible got signalled\n");
+		return -ERESTARTSYS;
+	}
+#ifdef CHNL_CHR_DEBUGFS
+	atomic_inc(&dev->num_close);
+#endif
+
+	/* Is the device open? */
+	if (!STATE_IS_OPEN(dev)) {
+		CAIFLOG_TRACE("[%s:%d] Device not open (dev=%p) \n",
+			      __func__, __LINE__, dev);
+		mutex_unlock(&dev->mutex);
+		return 0;
+	}
+
+	/* Is the device waiting for link setup response? */
+	if (STATE_IS_PENDING(dev)) {
+		CAIFLOG_TRACE("[%s:%d] Device is open pending (dev=%p) \n",
+			      __func__, __LINE__, dev);
+		mutex_unlock(&dev->mutex);
+		/* What to return here? Seems that EBADF is the closest :-| */
+		return -EBADF;
+	}
+
+	switch (filp->f_flags & O_ACCMODE) {
+	case O_RDONLY:
+		mode = CHR_READ_FLAG;
+		break;
+	case O_WRONLY:
+		mode = CHR_WRITE_FLAG;
+		break;
+	case O_RDWR:
+		mode = CHR_READ_FLAG | CHR_WRITE_FLAG;
+		break;
+	}
+
+
+	dev->file_mode &= ~mode;
+	if (dev->file_mode) {
+		CAIFLOG_TRACE
+		    ("Don't have permission to close"
+		     "CAIF connection - file_mode "
+		     "= %x\n", dev->file_mode);
+		mutex_unlock(&dev->mutex);
+		return 0;
+	}
+
+	/* IS_CLOSED have double meaning:
+	 * 1) Spontanous Remote Shutdown Request.
+	 * 2) Ack on a channel teardown(disconnect)
+	 * Must clear bit in case we previously received
+	 * remote shudown request.
+	 */
+
+	SET_STATE_CLOSED(dev);
+	SET_PENDING_ON(dev);
+	tx_flow_state_was_on = TX_FLOW_IS_ON(dev);
+	SET_TX_FLOW_OFF(dev);
+	result = caifdev_adapt_unregister(&dev->layer);
+
+	if (result < 0) {
+		CAIFLOG_TRACE
+		    ("caif_chrrelease: caifdev_adapt_unregister() failed\n");
+		SET_STATE_OPEN(dev);
+		tx_flow_state_was_on ? SET_TX_FLOW_ON(dev) :
+		    SET_TX_FLOW_OFF(dev);
+		mutex_unlock(&dev->mutex);
+		return -EIO;
+	}
+#ifdef CHNL_CHR_DEBUGFS
+	atomic_inc(&dev->num_deinit);
+#endif
+
+	/* We don't wait for close response here. Close pending state will be
+	   cleared by flow control callback when response arrives. */
+
+	/* Empty the queue */
+	drain_queue(dev);
+	SET_RX_FLOW_ON(dev);
+	dev->file_mode = 0;
+
+	IF_CAIF_TRACE(print_device_list());
+
+	mutex_unlock(&dev->mutex);
+	return 0;
+}
+
+const struct file_operations caif_chrfops = {
+	.owner = THIS_MODULE,
+	.read = caif_chrread,
+	.write = caif_chrwrite,
+	.open = caif_chropen,
+	.release = caif_chrrelease,
+	.poll = caif_chrpoll,
+};
+
+int chrdev_create(struct caif_channel_create_action *action)
+{
+
+	struct caif_char_dev *dev = NULL;
+	int result;
+	CAIFLOG_ENTER("");
+
+	IF_CAIF_TRACE(print_device_list());
+
+	/* Allocate device */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+
+	if (!dev) {
+		CAIFLOG_TRACE(KERN_ERR "chnl_chr: kmalloc failed.\n");
+		return -ENOMEM;
+	}
+
+	CAIFLOG_TRACE("[%s:%d] dev=%p \n", __func__, __LINE__, dev);
+	memset(dev, 0, sizeof(*dev));
+
+	mutex_init(&dev->mutex);
+	init_waitqueue_head(&dev->read_wq);
+	init_waitqueue_head(&dev->mgmt_wq);
+	spin_lock_init(&dev->read_queue_len_lock);
+
+	/* Fill in some information concerning the misc device. */
+	dev->misc.minor = MISC_DYNAMIC_MINOR;
+	strncpy(dev->name, action->name.name, sizeof(dev->name));
+	dev->misc.name = dev->name;
+	dev->misc.fops = &caif_chrfops;
+
+	/* Register the device */
+	result = misc_register(&dev->misc);
+
+	/* Lock in order to try to stop someone from opening the device
+	   too early. The misc device has its own lock. We cannot take our
+	   lock until misc_register() is finished, because in open() the
+	   locks are taken in this order (misc first and then dev).
+	   So anyone managing to open the device between the misc_register
+	   and the mutex_lock will get a "device not found" error. Don't
+	   think it can be avoided.
+	 */
+	mutex_lock_interruptible(&dev->mutex);
+
+	if (result < 0) {
+		CAIFLOG_ERROR("chnl_chr: error - %d, can't register misc.\n",
+			      result);
+		mutex_unlock(&dev->mutex);
+		goto err_failed;
+	}
+
+
+	dev->pktf = cfcnfg_get_packet_funcs();
+
+	dev->pktq = dev->pktf.cfpktq_create();
+	if (!dev->pktq) {
+		CAIFLOG_ERROR("chnl_chr: queue create failed.\n");
+		result = -ENOMEM;
+		mutex_unlock(&dev->mutex);
+		misc_deregister(&dev->misc);
+		goto err_failed;
+	}
+
+	CAIFLOG_TRACE("[%s:%d] pktf=%p\n", __func__, __LINE__, &dev->pktf);
+	CAIFLOG_TRACE("[%s:%d] cfpkt_create_xmit=%p\n", __func__,
+		      __LINE__, dev->pktf.cfpkt_create_xmit_pkt);
+
+	strncpy(action->name.name, dev->misc.name, sizeof(action->name.name));
+	action->major = MISC_MAJOR;
+	action->minor = dev->misc.minor;
+
+	dev->config = action->config;
+	CAIFLOG_TRACE("dev: Registered dev with name=%s minor=%d, dev=%p\n",
+		      dev->misc.name, dev->misc.minor, dev->misc.this_device);
+
+	dev->layer.ctrlcmd = caif_chrflowctrl_cb;
+	SET_STATE_CLOSED(dev);
+	SET_PENDING_OFF(dev);
+	SET_TX_FLOW_OFF(dev);
+	SET_RX_FLOW_ON(dev);
+
+	/* Add the device */
+	spin_lock(&list_lock);
+	list_add(&dev->list_field, &caif_chrdev_list);
+	spin_unlock(&list_lock);
+
+	IF_CAIF_TRACE(print_device_list());
+	printk(KERN_WARNING "chrdev_create: Creating device %s\n",
+	       action->name.name);
+
+#ifdef CHNL_CHR_DEBUGFS
+	if (debugfsdir != NULL) {
+		dev->debugfs_device_dir =
+		    debugfs_create_dir(dev->misc.name, debugfsdir);
+		debugfs_create_u32("conn_state", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir, &dev->conn_state);
+		debugfs_create_u32("flow_state", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir, &dev->flow_state);
+		debugfs_create_u32("num_open", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_open);
+		debugfs_create_u32("num_close", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_close);
+		debugfs_create_u32("num_init", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_init);
+		debugfs_create_u32("num_init_resp", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_init_resp);
+		debugfs_create_u32("num_init_fail_resp", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_init_fail_resp);
+		debugfs_create_u32("num_deinit", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_deinit);
+		debugfs_create_u32("num_deinit_resp", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_deinit_resp);
+		debugfs_create_u32("num_remote_shutdown_ind",
+				   S_IRUSR | S_IWUSR, dev->debugfs_device_dir,
+				   (u32 *) &dev->num_remote_shutdown_ind);
+		debugfs_create_u32("num_tx_flow_off_ind", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_tx_flow_off_ind);
+		debugfs_create_u32("num_tx_flow_on_ind", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_tx_flow_on_ind);
+		debugfs_create_u32("num_rx_flow_off", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_rx_flow_off);
+		debugfs_create_u32("num_rx_flow_on", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->num_rx_flow_on);
+		debugfs_create_u32("read_queue_len", S_IRUSR | S_IWUSR,
+				   dev->debugfs_device_dir,
+				   (u32 *) &dev->read_queue_len);
+	}
+#endif
+
+	CAIFLOG_EXIT("");
+	mutex_unlock(&dev->mutex);
+	return 0;
+err_failed:
+	action->name.name[0] = '\0';
+	action->major = -1;
+	action->minor = -1;
+	kfree(dev);
+	CAIFLOG_EXIT("");
+	return result;
+}
+
+
+int chrdev_remove(char *name)
+{
+	int ret = 0;
+
+	struct caif_char_dev *dev = NULL;
+	CAIFLOG_ENTER("");
+
+	IF_CAIF_TRACE(print_device_list());
+
+	/* Find device from name */
+	dev = find_device(-1, name, 0);
+	if (!dev)
+		return -EBADF;
+
+
+	mutex_lock_interruptible(&dev->mutex);
+
+	if (STATE_IS_OPEN(dev)) {
+		CAIFLOG_TRACE
+		    ("[%s:%d] Device is opened (dev=%p) file_mode = 0x%x\n",
+		     __func__, __LINE__, dev, dev->file_mode);
+		mutex_unlock(&dev->mutex);
+		return -EBUSY;
+	}
+
+	/* Remove from list */
+	(void) find_device(-1, name, 1);
+
+	drain_queue(dev);
+	ret = misc_deregister(&dev->misc);
+
+	cfglu_free(dev->pktq);
+
+#ifdef CHNL_CHR_DEBUGFS
+	if (dev->debugfs_device_dir != NULL)
+		debugfs_remove_recursive(dev->debugfs_device_dir);
+#endif
+
+	mutex_unlock(&dev->mutex);
+	printk(KERN_WARNING "chrdev_remove: Removing device %s\n", dev->name);
+	kfree(dev);
+
+	IF_CAIF_TRACE(print_device_list());
+
+
+	return ret;
+}
+
+
+int chrdev_mgmt(int action, union caif_action *param)
+{
+
+	switch (action) {
+	case CAIF_ACT_CREATE_DEVICE:
+		return chrdev_create(&param->create_channel);
+	case CAIF_ACT_DELETE_DEVICE:
+		return chrdev_remove(param->delete_channel.name);
+	default:
+		return -EINVAL;
+	}
+}
+
+int caif_chrinit_module(void)
+{
+	CAIFLOG_ENTER("");
+	CAIFLOG_TRACE("\nCompiled:%s:%s\n", __DATE__, __TIME__);
+
+#ifdef CHNL_CHR_DEBUGFS
+	debugfsdir = debugfs_create_dir("chnl_chr", NULL);
+#endif
+
+	spin_lock_init(&list_lock);
+	caif_register_chrdev(chrdev_mgmt);
+	return 0;
+}
+
+void caif_chrexit_module(void)
+{
+	int result;
+
+	CAIFLOG_ENTER("");
+	IF_CAIF_TRACE(print_device_list());
+
+	do {
+		/* Remove any device (the first in the list) */
+		result = chrdev_remove(NULL);
+	} while (result == 0);
+
+	caif_unregister_chrdev();
+
+#ifdef CHNL_CHR_DEBUGFS
+	if (debugfsdir != NULL)
+		debugfs_remove_recursive(debugfsdir);
+#endif
+
+	IF_CAIF_TRACE(print_device_list());
+	CAIFLOG_EXIT("");
+}
+
+module_init(caif_chrinit_module);
+module_exit(caif_chrexit_module);
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
new file mode 100644
index 0000000..ce13968
--- /dev/null
+++ b/net/caif/chnl_net.c
@@ -0,0 +1,492 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2 or later.
+*
+*/
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/moduleparam.h>
+#include <linux/ip.h>
+
+/* Caif header files. */
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfpkt.h>
+
+#include <net/caif/caif_chr.h>
+#include <net/caif/caif_log.h>
+
+#define CAIF_CONNECT_TIMEOUT 30
+#define SIZE_MTU 1500
+#define SIZE_MTU_MAX 4080
+#define SIZE_MTU_MIN 68
+
+static LIST_HEAD(chnl_net_list);
+static spinlock_t list_lock;
+
+MODULE_LICENSE("GPL");
+
+static int loop;
+module_param(loop, bool, S_IRUGO);
+MODULE_PARM_DESC(loop, "Loop enabled or not "
+		"(looping will switch src and dest of transmitted packages)");
+
+struct chnl_net {
+	layer_t chnl;
+	struct net_device_stats stats;
+	spinlock_t lock;
+	struct caif_channel_config config;
+	struct list_head list_field;
+	struct net_device *netdev;
+	char name[256];
+	wait_queue_head_t netmgmt_wq;
+	/* Flow status to remember and control the transmission */
+	bool flowenabled;
+};
+
+static struct chnl_net *find_device(char *name, bool remove_from_list)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct chnl_net *dev = NULL;
+	struct chnl_net *tmp;
+	CAIFLOG_ENTER("");
+	spin_lock(&list_lock);
+	CAIFLOG_TRACE("[%s:%d] start looping \n", __func__,
+		__LINE__);
+	list_for_each_safe(list_node, n, &chnl_net_list) {
+		tmp =
+			list_entry(list_node, struct chnl_net, list_field);
+		/* find from name */
+		if (name) {
+			if (!strncmp(tmp->name, name, sizeof(tmp->name)))
+				dev = tmp;
+		} else
+			/* Get the first element
+			 * if name is not specified */
+			dev = tmp;
+		if (dev) {
+			CAIFLOG_TRACE("[%s:%d] match %s \n",
+				__func__, __LINE__,  name);
+			if (remove_from_list)
+				list_del(list_node);
+			break;
+		}
+	}
+	spin_unlock(&list_lock);
+	return dev;
+}
+
+
+
+static int chnl_recv_cb(layer_t *layr, cfpkt_t *pkt)
+{
+	struct sk_buff *skb;
+	caif_packet_funcs_t f;
+	struct chnl_net *priv  = NULL;
+	int pktlen;
+
+#ifdef CAIF_USE_SKB
+#else
+	int actual_len;
+#endif
+	int err = 0;
+
+	priv = container_of(layr, struct chnl_net, chnl);
+
+	if (!priv) {
+		CAIFLOG_TRACE("chnl_recv_cb: netdev container not found\n");
+		return -EINVAL;
+	}
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+	/* Get length of caif packet. */
+	pktlen = f.cfpkt_getlen(pkt);
+
+
+#ifdef CAIF_USE_SKB
+	skb = (struct sk_buff *) f.cfpkt_tonative(pkt);
+#else
+	skb = dev_alloc_skb(pktlen);
+
+	if (!skb) {
+		CAIFLOG_TRACE("chnl_recv_cb: dev_alloc_skb failed.\n");
+		/* Update statistics. */
+		priv->netdev->stats.rx_dropped++;
+		err = -ENOMEM;
+		goto err_alloc_skb;
+	}
+
+	/* Extract data from the caif packet and copy it to the skb. */
+	f.cfpkt_extract(pkt, skb_put(skb, pktlen), pktlen, &actual_len);
+#endif
+	/* Pass some minimum information and
+	 * send the packet to the net stack. */
+	skb->dev = priv->netdev;
+	skb->protocol = htons(ETH_P_IP);
+	skb->ip_summed = CHECKSUM_COMPLETE;
+
+	/*FIXME: Drivers should call this in tasklet context*/
+	if (in_interrupt())
+		netif_rx(skb);
+	else
+		netif_rx_ni(skb);
+
+	/* Update statistics. */
+	priv->netdev->stats.rx_packets++;
+	priv->netdev->stats.rx_bytes += pktlen;
+
+#ifdef CAIF_USE_SKB
+#else
+err_alloc_skb:
+	f.cfpkt_destroy(pkt);
+#endif
+	return err;
+}
+
+static void chnl_flowctrl_cb(layer_t *layr, caif_ctrlcmd_t flow,int phyid)
+{
+	struct chnl_net *priv  = NULL;
+	CAIFLOG_TRACE("NET flowctrl func called flow: %s.\n",
+		flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
+		flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
+		flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
+		flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" :
+		flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" :
+		flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ?
+		 "REMOTE_SHUTDOWN" : "UKNOWN CTRL COMMAND");
+
+	priv = container_of(layr, struct chnl_net, chnl);
+
+	switch (flow) {
+	case CAIF_CTRLCMD_FLOW_OFF_IND:
+	case CAIF_CTRLCMD_DEINIT_RSP:
+	case CAIF_CTRLCMD_INIT_FAIL_RSP:
+	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+		priv->flowenabled = false;
+		netif_tx_disable(priv->netdev);
+		wake_up_interruptible(&priv->netmgmt_wq);
+	break;
+	case CAIF_CTRLCMD_FLOW_ON_IND:
+	case CAIF_CTRLCMD_INIT_RSP:
+		priv->flowenabled = true;
+		netif_wake_queue(priv->netdev);
+		wake_up_interruptible(&priv->netmgmt_wq);
+	break;
+	default:
+		break;
+	}
+}
+
+static int chnl_net_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct chnl_net *priv;
+	cfpkt_t *pkt = NULL;
+	int len;
+	caif_packet_funcs_t f;
+	int result = -1;
+
+	/* Get our private data. */
+	priv = (struct chnl_net *)netdev_priv(dev);
+	if (!priv) {
+		CAIFLOG_TRACE("chnl_write: priv not found\n");
+#ifndef CAIF_USE_SKB
+			goto err_cfpkt_create;
+#else
+			return -ENOSPC;
+#endif
+	}
+
+	if (skb->len > priv->netdev->mtu) {
+		CAIFLOG_TRACE("chnl_write ERR:"
+			" Size of skb packet exceeded size of set MTU\n");
+#ifndef CAIF_USE_SKB
+			goto err_cfpkt_create;
+#else
+			return -ENOSPC;
+#endif
+	}
+
+	if (!priv->flowenabled) {
+#ifndef CAIF_USE_SKB
+			dev_kfree_skb(skb);
+#endif
+		CAIFLOG_TRACE("Dropping packets Flow OFF\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	if (loop) {
+		struct iphdr *hdr;
+		__be32 swap;
+		/* Retrieve IP header. */
+		hdr = ip_hdr(skb);
+		/* Change source and destination address. */
+		swap = hdr->saddr;
+		hdr->saddr = hdr->daddr;
+		hdr->daddr = swap;
+	}
+	/* Store original skb length. */
+	len = skb->len;
+
+	/* Get caif packet functions. */
+	f = cfcnfg_get_packet_funcs();
+
+#ifdef CAIF_USE_SKB
+	pkt = f.cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
+#else
+	/* Create a caif packet based on the skbuf. */
+	pkt = f.cfpkt_create_xmit_pkt(skb->data, skb->len);
+	if (!pkt) {
+		CAIFLOG_TRACE("chnl_write: cfpkt_create failed.\n");
+		goto err_cfpkt_create;
+	}
+#endif
+
+	/* Send the packet down the stack. */
+	result = priv->chnl.dn->transmit(priv->chnl.dn, NULL, pkt);
+	if (result) {
+		if (result == CFGLU_ERETRY)
+			result = NETDEV_TX_BUSY;
+
+#ifndef CAIF_USE_SKB
+		f.cfpkt_destroy(pkt);
+#endif
+		return result;
+	}
+
+	/* Update statistics. */
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += len;
+
+#ifndef CAIF_USE_SKB
+	dev_kfree_skb(skb);
+#endif
+	return NETDEV_TX_OK;
+
+#ifndef CAIF_USE_SKB
+err_cfpkt_create:
+	dev_kfree_skb(skb);
+	return -ENOSPC;
+#endif
+}
+
+static int chnl_net_change_mtu(struct net_device *dev, int mtu)
+{
+	unsigned long flags;
+	struct chnl_net *priv = netdev_priv(dev);
+	spinlock_t *lock = &priv->lock;
+
+	/* check range. MTU can not exceed maximum
+	 * CAIF frame size (4095 bytes) */
+	if ((mtu < SIZE_MTU_MIN) || (mtu > SIZE_MTU_MAX))
+		return -EINVAL;
+
+	spin_lock_irqsave(lock, flags);
+	dev->mtu = mtu;
+	spin_unlock_irqrestore(lock, flags);
+	return 0;
+}
+
+
+static int chnl_net_open(struct net_device *dev)
+{
+	struct chnl_net *priv = NULL;
+	int result = -1;
+
+	CAIFLOG_ENTER("chnl_net_open:\n");
+	priv = (struct chnl_net *)netdev_priv(dev);
+	CAIFLOG_TRACE("chnl_net_open dev name: %s\n", priv->name);
+
+	if (!priv) {
+		CAIFLOG_TRACE("chnl_net_open: no priv\n");
+		return -ENODEV;
+	}
+	result = caifdev_adapt_register(&priv->config, &priv->chnl);
+	if (result != 0) {
+		CAIFLOG_TRACE("chnl_net_open: err: "
+			      "Unable to register and open device, Err:%d\n",
+			       result);
+		return -ENODEV;
+	}
+	result = wait_event_interruptible(priv->netmgmt_wq, priv->flowenabled);
+
+	if (result == -ERESTARTSYS) {
+		CAIFLOG_TRACE
+		   ("chnl_net_open: "
+		     "wait_event_interruptible woken by a signal\n");
+		return -ERESTARTSYS;
+	} else
+		CAIFLOG_TRACE("chnl_net_open: Flow on recieved\n");
+
+
+	CAIFLOG_EXIT("chnl_net_open:\n");
+	return 0;
+}
+
+static int chnl_net_stop(struct net_device *dev)
+{
+	struct chnl_net *priv;
+	int result = -1;
+	CAIFLOG_ENTER("chnl_net_stop:\n");
+	CAIFLOG_TRACE("chnl_net_stop: %s \n", dev->name);
+	priv = (struct chnl_net *)netdev_priv(dev);
+
+	result = caifdev_adapt_unregister(&priv->chnl);
+	if (result != 0) {
+		CAIFLOG_TRACE("chnl_net_stop: err: "
+			      "Unable to STOP device, Err:%d\n", result);
+		return -EBUSY;
+	}
+	result = wait_event_interruptible(priv->netmgmt_wq,
+					  !priv->flowenabled);
+
+	if (result == -ERESTARTSYS) {
+		CAIFLOG_TRACE
+		    ("chnl_net_stop: "
+		     "wait_event_interruptible woken by signal,"
+		     " signal_pending(current) = %d\n",
+		     signal_pending(current));
+	} else {
+		CAIFLOG_TRACE("[%s:%d] chnl_net_stop: DISCONNECT RECEIVED\n",
+			      __func__, __LINE__);
+	}
+
+	CAIFLOG_EXIT("chnl_net_stop:\n");
+	return 0;
+}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static const struct net_device_ops netdev_ops = {
+	.ndo_open = chnl_net_open,
+	.ndo_stop = chnl_net_stop,
+	.ndo_change_mtu = chnl_net_change_mtu,
+	.ndo_start_xmit = chnl_net_hard_start_xmit,
+};
+#endif
+
+static void chnl_net_init(struct net_device *dev)
+{
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28))
+	CAIFLOG_ENTER("chnl_net_init:\n");
+	dev->open = chnl_net_open;
+	dev->stop = chnl_net_stop;
+	dev->hard_xmit = chnl_net_hard_start_xmit;
+#else
+
+	CAIFLOG_ENTER("chnl_net_init:\n");
+	dev->netdev_ops = &netdev_ops;
+#endif
+	dev->flags |= IFF_NOARP;
+	dev->needed_headroom = CAIF_NEEDED_HEADROOM;
+	dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
+	dev->mtu = SIZE_MTU;
+	CAIFLOG_EXIT("chnl_net_init:\n");
+}
+
+
+static int netdev_create(struct caif_channel_create_action *action)
+{
+	struct chnl_net *priv;
+	int result = -1;
+	struct net_device *netdevptr;
+
+	netdevptr = alloc_netdev(sizeof(struct chnl_net),
+				 action->name.name, chnl_net_init);
+	if (!netdevptr) {
+		CAIFLOG_TRACE("chnl: can't allocate netdev.\n");
+		return	-ENODEV;
+	}
+	priv = (struct chnl_net *)netdev_priv(netdevptr);
+	priv->chnl.receive = chnl_recv_cb;
+	priv->chnl.ctrlcmd = chnl_flowctrl_cb;
+	priv->config = action->config;
+	priv->netdev = netdevptr;
+	priv->flowenabled = false;
+	init_waitqueue_head(&priv->netmgmt_wq);
+	strncpy(priv->name, action->name.name, sizeof(priv->name));
+
+	/* Make sure flow is disabled until INIT_RSP is received. */
+	netif_tx_disable(priv->netdev);
+
+	result = register_netdev(priv->netdev);
+	if (result < 0) {
+		CAIFLOG_TRACE("chnl: err: %d, can't register netdev.\n",
+			      result);
+		free_netdev(priv->netdev);
+		return	-ENODEV;
+	}
+	CAIFLOG_TRACE("netdev_create: Created channel: %s\n", priv->name);
+
+	/* Add the device to the list*/
+	spin_lock_init(&priv->lock);
+	spin_lock(&list_lock);
+	list_add(&priv->list_field, &chnl_net_list);
+	spin_unlock(&list_lock);
+
+	return 0;
+}
+
+static int delete_device(struct chnl_net *dev)
+{
+	CAIFLOG_TRACE("delete_device: Removing Device: %s\n", dev->name);
+	if (dev->netdev) {
+		unregister_netdev(dev->netdev);
+		free_netdev(dev->netdev);
+	}
+	return 0;
+}
+
+static int netdev_remove(char *name)
+{
+	struct chnl_net *dev = NULL;
+	/* Find device from name */
+	dev = find_device(name, true);
+	if (!dev)
+		return -EBADF;
+	else
+		if (delete_device(dev) != 0)
+			return -EBUSY;
+	return 0;
+}
+
+
+static int netdev_mgmt(int action, union caif_action *param)
+{
+	switch (action) {
+	case CAIF_ACT_CREATE_DEVICE:
+		return netdev_create(&param->create_channel);
+	case CAIF_ACT_DELETE_DEVICE:
+		return netdev_remove(param->delete_channel.name);
+	default:
+		return -EINVAL;
+	}
+}
+
+int chnl_init_module(void)
+{
+	caif_register_netdev(netdev_mgmt);
+	return 0;
+}
+
+void chnl_exit_module(void)
+{
+	struct chnl_net *dev = NULL;
+
+	/* find_device with NULL removes the first
+	 * element from the list and updates the list*/
+	while ((dev = find_device(NULL, true)) != NULL)
+		delete_device(dev);
+
+	caif_unregister_netdev();
+}
+
+module_init(chnl_init_module);
+module_exit(chnl_exit_module);
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 6/8-v2] CAIF Protocol Stack
  2009-10-09 13:39         ` [PATCH] [CAIF-RFC 5/8-v2] " sjur.brandeland
@ 2009-10-09 13:39           ` sjur.brandeland
  2009-10-09 13:39             ` [PATCH] [CAIF-RFC 7/8-v2] " sjur.brandeland
  2009-10-12 13:06             ` [PATCH] [CAIF-RFC 6/8-v2] " Stefano Babic
  2009-10-09 16:43           ` [PATCH] [CAIF-RFC 5/8-v2] " Randy Dunlap
  2009-10-12 12:51           ` Stefano Babic
  2 siblings, 2 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: I7888e9b5aed8914036a87fdc6622697eacb27b2e
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 drivers/net/caif/Kconfig      |   23 +++
 drivers/net/caif/Makefile     |   26 ++++
 drivers/net/caif/phyif_loop.c |  308 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/caif/phyif_ser.c  |  189 +++++++++++++++++++++++++
 4 files changed, 546 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/caif/Kconfig
 create mode 100644 drivers/net/caif/Makefile
 create mode 100644 drivers/net/caif/phyif_loop.c
 create mode 100644 drivers/net/caif/phyif_ser.c

diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
new file mode 100644
index 0000000..bc19226
--- /dev/null
+++ b/drivers/net/caif/Kconfig
@@ -0,0 +1,23 @@
+#
+# CAIF Physical drivers
+#
+
+if CAIF
+
+comment "CAIF physical drivers"
+
+config CAIF_TTY
+	tristate "CAIF TTY transport driver"
+	default n
+	---help---
+	The CAIF TTY transport driver.
+	If you say yes here you will also need to build a userspace utility to set the line disicpline on the
+	tty, see Documentation/CAIF/linedsc.
+
+config CAIF_LOOPBACK
+	tristate "CAIF loopback driver test driver"
+	default n
+	---help---
+	Loopback test driver
+
+endif # CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
new file mode 100644
index 0000000..a84049a
--- /dev/null
+++ b/drivers/net/caif/Makefile
@@ -0,0 +1,26 @@
+
+ifeq ($(CONFIG_CAIF_USE_PLAIN),1)
+CFPKT:=plain
+else
+CFPKT:=skbuff
+CAIF_FLAGS+=-DCAIF_USE_SKB
+endif
+
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_FLAGS+=-DCAIF_DEBUG_ON
+endif
+
+
+ccflags-y :=  $(CAIF_FLAGS)
+
+
+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
\ No newline at end of file
diff --git a/drivers/net/caif/phyif_loop.c b/drivers/net/caif/phyif_loop.c
new file mode 100644
index 0000000..bb17bc7
--- /dev/null
+++ b/drivers/net/caif/phyif_loop.c
@@ -0,0 +1,308 @@
+/*
+ *	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 <net/caif/caif_log.h>
+#include <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfpkt.h>
+
+#include <net/caif/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);
+
+	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 __exit 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..6e1337c
--- /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 <net/caif/generic/caif_layer.h>
+#include <net/caif/generic/cfcnfg.h>
+#include <net/caif/generic/cfpkt.h>
+#include <net/caif/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 __exit 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);
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 7/8-v2] CAIF Protocol Stack
  2009-10-09 13:39           ` [PATCH] [CAIF-RFC 6/8-v2] " sjur.brandeland
@ 2009-10-09 13:39             ` sjur.brandeland
  2009-10-09 13:39               ` [PATCH] [CAIF-RFC 8/8-v2] " sjur.brandeland
  2009-10-12 13:43               ` [PATCH] [CAIF-RFC 7/8-v2] " Stefano Babic
  2009-10-12 13:06             ` [PATCH] [CAIF-RFC 6/8-v2] " Stefano Babic
  1 sibling, 2 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Change-Id: I6cb476abc44bf49ac74562178dba7b6e47c2e342
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
 Documentation/CAIF/Linux-CAIF.txt                  |  318 +++++++++++++++++
 Documentation/CAIF/README                          |   60 ++++
 Documentation/CAIF/caif_user_config.dox            |  105 ++++++
 Documentation/CAIF/chardevconfig/Makefile          |   11 +
 Documentation/CAIF/chardevconfig/README            |   39 ++
 Documentation/CAIF/chardevconfig/caif_cmd_parse.c  |  366 ++++++++++++++++++++
 Documentation/CAIF/chardevconfig/caif_cmd_parse.h  |   22 ++
 Documentation/CAIF/chardevconfig/chardevconfig.c   |  110 ++++++
 .../CAIF/chardevconfig/create_devices.config       |    1 +
 .../CAIF/chardevconfig/delete_devices.config       |    1 +
 Documentation/CAIF/ldiscd/README                   |   12 +
 Documentation/CAIF/ldiscd/ldiscd.c                 |  123 +++++++
 Documentation/DocBook/caif.tmpl                    |  238 +++++++++++++
 13 files changed, 1406 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/CAIF/Linux-CAIF.txt
 create mode 100644 Documentation/CAIF/README
 create mode 100644 Documentation/CAIF/caif_user_config.dox
 create mode 100644 Documentation/CAIF/chardevconfig/Makefile
 create mode 100644 Documentation/CAIF/chardevconfig/README
 create mode 100644 Documentation/CAIF/chardevconfig/caif_cmd_parse.c
 create mode 100644 Documentation/CAIF/chardevconfig/caif_cmd_parse.h
 create mode 100644 Documentation/CAIF/chardevconfig/chardevconfig.c
 create mode 100644 Documentation/CAIF/chardevconfig/create_devices.config
 create mode 100644 Documentation/CAIF/chardevconfig/delete_devices.config
 create mode 100644 Documentation/CAIF/ldiscd/README
 create mode 100644 Documentation/CAIF/ldiscd/ldiscd.c
 create mode 100644 Documentation/DocBook/caif.tmpl

diff --git a/Documentation/CAIF/Linux-CAIF.txt b/Documentation/CAIF/Linux-CAIF.txt
new file mode 100644
index 0000000..26faba6
--- /dev/null
+++ b/Documentation/CAIF/Linux-CAIF.txt
@@ -0,0 +1,318 @@
+Linux CAIF
+===========
+
+Introduction
+------------
+CAIF is a MUX protocol used by ST-Ericsson cellular modems for
+communication
+between Modem and host. The host processes can open virtual AT
+channels, initiate GPRS Data connections, Video channels and
+Utility Channels.
+The Utility Channels are general purpose pipes between modem
+and host.
+
+ST-Ericsson modems support a number of transports between modem
+and host,
+currently Uart and Shared Memory are available for Linux.
+
+Architecture:
+------------
+The Implementation of CAIF is divided into:
+* CAIF Drivers: Character Device, Net Device and Kernel API.
+* CAIF Generic Protocol Implementation
+* CAIF Link Layer
+
+CAIF is using IOCTLs to manage the CAIF Drivers.
+
+
+  IOCTL
+   !
+   !     +------+   +------+   +------+
+   !    +------+!  +------+!  +------+!
+   !    ! Char !!  !Kernel!!  ! Net  !!
+   !    ! Dev  !+  ! API  !+  ! Dev  !+   <- CAIF Drivers
+   !    +------+   +------!   +------+
+   !       !          !          !
+   !       +----------!----------+
+   !               +------+               <- CAIF Protocol Implementation
+   +------->       ! CAIF !                  /dev/caifconfig
+                   +------+
+             +--------!--------+
+             !                 !
+          +------+          +-----+
+          !ShMem !          ! TTY !       <- Link Layer
+          +------+          +-----+
+
+
+
+Using CAIF Character Device
+-----------------------------
+CAIF character devices are configured by use of IOCTLs on the
+node "/dev/caifconfig". E.g. the following code will create an
+CAIF Character Device that will make an AT channel accessible:
+
+   struct caif_channel_create_action at = {
+	.name = {
+	   .name = "cnhlatl",
+	   .type = CAIF_DEV_CHR
+        },
+	.config = {
+	    .channel = CAIF_CHTY_AT,
+	 }};
+   fd = open("/dev/caifconfig",..);
+   ioctl(fd, CAIF_IOC_CONFIG_DEVICE,&at_config);
+
+A configuration tool chardevconfig exist in order to simplify
+creation of CAIF Channels (typically used from init scripts).
+E.g:
+
+   $chardevconfig /dev/caifconfig -
+   CREATE TYPE=AT NAME=chnlat1 DEVTYPE=CHAR PHYPREF=BW
+
+This will result in creation of the device node "/dev/chnlat1".
+"/dev/chnlat1" can be used to read and write AT commands and
+responses from the modem:
+
+   $cat /dev/chnlat1 &
+   $printf "AT\r" > /dev/chnlat1
+   OK
+
+
+
+Using CAIF Net Device
+----------------------
+CAIF Net device can be created similarly as the character
+device.
+E.g:
+
+   $chardevconfig /dev/caifconfig -
+   CREATE TYPE=DGM NAME=caif0 DEVTYPE=NET CONNID=1 ^D
+
+   $ifconfig caif0 <ip address> up
+
+
+Using the Kernel API
+----------------------
+The Kernel API is used for accessing CAIF channels from the
+kernel.
+The user of the API has to implement two callbacks for receive
+and control.
+The receive callback give a CAIF packet as a SKB. The control
+callback will
+notify about channel initialization complete, and flow-on/flow-
+off.
+
+
+  struct caif_device caif_dev = {
+    .caif_config = {
+     .name = "MYDEV"
+     .type = CAIF_CHTY_AT
+    }
+   .receive_cb = my_receive,
+   .control_cb = my_control,
+  };
+
+  caif_add_device(&caif_dev);
+
+  caif_transmit(&caif_dev, skb);
+
+
+See the caif_kernel.h for details about the CAIF kernel API.
+
+
+
+
+
+
+
+
+I M P L E M E N T A T I O N
+===========================
+===========================
+
+
+
+
+GenCAIF - The Generic CAIF Protocol Layer
+=========================================
+
+
+GenCaif is a generic CAIF protocol implementation. It implements the CAIF
+protocol as defined by ST-Ericsson.
+GenCaif implements the CAIF protocol stack in a layered approach, where
+each layer described in the specification is implemented as a separate layer.
+The architecture is inspired by the design patterns "Protocol Layer" and
+"Protocol Packet".
+
+== CAIF structure ==
+
+The goal is to have caif as system independent as possible.
+All caif code can be found under GenCaif/src and GenCaif/inc.
+The actual linux module implementation is under src/kernel.
+There is also a user space program that is not up to date to run the stack in
+user space for testing.
+
+We have tested the kernel implementation on the emulator with a modem and we
+are able to enumerate and make a link setup.
+
+GenCAIF is:
+      -	Simple implementation of CAIF.
+      -	Layered architecture (ala Streams), each layer specified CAIF
+        specification is implemented in a separate c-file.
+      -	Client of GenCaif must implement PHY layer to access physical HW
+	with receive and transmit functions.
+      -	Client of GenCaif must call configuration function add PHY layer.
+      -	Client of GenCaif must implement adaptation layer to consume/produce
+        CAIF payload with receive and transmit functions.
+      -	Client of GenCaif  must call configuration function add adaptation
+        layer.
+      - When receiving / transmitting CAIF Packets (cfpkt) ownership is passed
+        to the called function (except Framinglayer's receive function).
+
+
+
+Layered Architecture
+--------------------
+The CAIF protocol can be divided into two parts Support functions and Protocol
+Implementation. The support functions include:
+
+      - CFPKT CAIF Packet. Implementation of CAIF Protocol Packet. The
+        CAIF Packet has functions for creating,destroying, adding content, and
+        adding/extracting header and trailers to protocol packets.
+
+      - CFLST CAIF list implementation.
+
+      - CFGLUE CAIF Glue. Contains OS Specifics such as memory
+        allocation, endianness etc.
+
+
+The CAIF Protocol implementation contains:
+
+      - CFCNFG CAIF Configuration layer. Configures the CAIF Protocol
+        Stack, and has Client interface for adding Link-Layer and
+	Driver interfaces on top of the CAIF Stack.
+
+      - CFCTRL CAIF Control layer. Encodes and Decodes control messages
+	such as enumeration, and channel setup. And matches request and
+	response messages.
+
+      - CFSERVL General CAIF Service Layer functionality, handle flow
+	control and remote shutdown requests.
+
+      - CFVEI CAIF VEI layer. Handles CAIF VEI layer (AT-Channel),
+        code/encodes VEI frames.
+
+      - CFDGML CAIF Data-gram layer. Handles CAIF Data-gram layer(IP
+        traffic), code/encodes Datagram frames.
+
+      - CFMUX CAIF Mux layer. Handles multiplexing between multiple
+        physical bearers and multiple channels such as VEI, Data-gram etc
+	The MUX is keeping track of the existing CAIF Channels and
+	Physical Instances and selects the apropriate instance based
+	on Channel-Id and Physical-ID.
+
+      - CFFRML CAIF Framing layer. Handles Framing i.e. Frame length
+        and frame checksum.
+
+      - CFSERL CAIF Serial layer. Handles concatenation/split of frames
+        into CAIF Frames with correct length.
+
+      - CFSHML CAIF Shared Memory layer.
+
+
+
+                    +---------+
+                    | Config  |
+                    | CFCNFG  |
+                    +---------+
+                         !
+    +---------+     +---------+     +---------+
+    |   AT    |     | Control |     | Datagram|
+    | CFVEIL  |     | CFCTRL  |     | CFDGML  |
+    +---------+     +---------+     +---------+
+           \_____________!______________/
+                         !
+                    +---------+
+                    |   MUX   |
+                    |         |
+                    +---------+
+                    _____!_____
+                   /           \
+            +---------+     +---------+
+            | CFFRML  |     | CFFRML  |
+            | Framing |     | Framing |
+            +---------+     +---------+
+                 !              !
+            +---------+     +---------+
+            | Sh-Mem  |     | Serial  |
+            | CFSHML  |     | CFSERL  |
+            +---------+     +---------+
+
+
+
+In this layered approach the following "rules" applies.
+      - All layers embedd the same structure 'struct layer'
+      - Layer do not depend on any others layer private data.
+      - Layers are stacked by setting the pointers
+		  layer->up , layer->dn
+      -	In order to send data upwards each layer should do
+		 layer->up->receive(layer->up, packet);
+      - In oder to send data downwards each layer should do
+		 layer->dn->transmit(layer->dn, packet);
+
+
+
+Linux Driver Implementation
+===========================
+
+Linux GPRS Net Device and Character Devices are implemented on top of the
+Generic CAIF protocol. The Net device and Chr device has an instance of
+'struct layer' as the generic caif protocol stack.
+Net and Chr device implements the 'receive()' function defined by
+'struct layer' as the rest of the CAIF stack. In this way transmit and
+reception of packets is handled as the rest of the layers, 'dn->transmit()'
+function is called in order to tranmit data.
+
+The layer on top of the Generic CAIF is called an "adaptation layer".
+
+
+Configuration of Drivers
+------------------------
+
+Configuration is the most complex part of the CAIF protocol.
+Configuration is controlled by the Misc device 'caifconfig'
+implemented in caif_chr. A device is created when a IOCTL
+command for creation is received containing information about
+the CAIF Channel type to be created and the type of device to instanciate
+(Net Device or Character Device).
+
+The Net Device and Character Device will register into the 'caifconfig'
+device by calling 'caif_register_netdev' and 'caif_register_chrdev'.
+When registered the 'caifconfig' module will keep function pointers
+to the devices used when IOCTL creates new devices.
+
+
+The CAIF Configuration module CFCNFG is responsible for connecting and
+setting up the entire CAIF stack.
+
+The function 'cfcnfg_add_adapt_layer' is used to connect a Linux Driver
+to the ST-Ericsson modem. This function will trigger the setup of CAIF
+Channel by sending a "LinkSetup" message to the modem. When the
+"LinkSetupResponse" is received the CAIF protocol for the requested
+CAIF Service will be set up.
+
+The CAIF Channel configuration parameters will be given as input.
+
+
+
+Configuration of Link Layer
+---------------------------
+The Link Layer (or Phy Layer) must implement the 'transmit' function
+defined by 'struct layer' in order to send payload. When data is received
+the Link Layer calls 'up->receive()'.
+Configuring the link layer is done by the function 'cfcnfg_add_phy_layer'.
+This function will set up the CAIF Layers for the new Link Layer.
+
+
+The physical Link Layers registers intself into 'caifconfig' by
+calling the function 'caif_phy_register()'.
diff --git a/Documentation/CAIF/README b/Documentation/CAIF/README
new file mode 100644
index 0000000..a8c43cb
--- /dev/null
+++ b/Documentation/CAIF/README
@@ -0,0 +1,60 @@
+copyright (C) ST-Ericsson AB 2009
+Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+        Kim Lilliestierna Kim.xx.Lilliestierna@ericsson.com
+License terms: GNU General Public License (GPL), version 2.
+
+=== Start ===
+Copy the .ko files onto the board, and do insmod:
+
+insmod caif.ko
+insmod phyif_loop.ko
+insmod chnl_chr.ko
+insmod chnl_net.ko
+ifconfig caif0 <your-home-address> up
+
+
+=== Test Loopback on net device ===
+insmod chnl_net.ko loop=yes
+ifconfig caif0 192.168.0.1 up
+ping -c 10 -s 1000 192.168.0.2
+
+=== Preparing the setup.===
+
+Make sure that the kernel is built with module support.
+
+There are some things that need to be
+tweaked to get the host TTY correctly setup to talk to the modem.
+Since the CAIF stack is running in the kernel and we want to use the existing
+TTY we are installing our physical serial driver as a line discipline above
+the TTY device.
+
+To achieve this we need the help of a daemon program called ldiscd.
+The benefit is that we can hook up to any TTY, the downside is that we need
+an extra operation in order to install the line discipline.
+
+Getting the host TTY to behave (This should only be necessary when running
+on the emulator, otherwise the ldiscd should correctly configure the UART).
+
+Retrieve the current settings:
+
+$ stty -a -F /dev/ttyUSB1
+
+Make sure that we are having 115200, 8n1, CTS/RTS (for example if CTS/RTS is missing):
+$ stty -F /dev/ttyUSB1 ctsrts
+
+Build the line discipline daemon. (You need to change CAIF_LDISC_TTY
+if your not using /dev/ttyS0.)
+
+$ gcc ldiscd.c -o ldisc
+
+Install the line discipline (daemon)
+$ ldisc
+
+Install the VEI channel (this will enumerate and do the linksetup of the first VEI channel. If this goes well you should see /dev/chn*) (There are printks logging all buffers that can be checked with dmesg):
+$ modprobe chnl_chr
+
+The AT (VEI) channel is ready to use (you can now send AT commands on it):
+$ echo -e "AT\r\n" > /dev/chnlat10
+
+Verify that you got an OK response (There are printks logging all buffers that can be checked with dmesg):
+$ cat /dev/chnlat10
diff --git a/Documentation/CAIF/caif_user_config.dox b/Documentation/CAIF/caif_user_config.dox
new file mode 100644
index 0000000..4753139
--- /dev/null
+++ b/Documentation/CAIF/caif_user_config.dox
@@ -0,0 +1,105 @@
+/*
+*      Copyright (C) ST-Ericsson AB 2009
+*
+*      CAIF User Space API for CAIF Channels.
+*
+*      Author: Sjur Brændeland/ sjur.brandeland@stericsson.com
+*
+*      License terms: GNU General Public License (GPL), version 2 or later.
+*/
+
+
+/**
+\defgroup  caif_config Configuring CAIF
+\section CAIF Configiration  basics
+CAIF is configured by ioctl's agains the CAIF configuration device normally \b "/dev/caifconfig"
+
+The ioctl structurs can either be populated manually or the cmd_parse utility from GenCaif can be
+used to parse a higlevel commands string and populate the itoctl structure correctly.
+
+This method is used by the chrdevconfig utility that also can be used to configure  CAIF and is typically used by the init system.
+
+Since the high level command language is a direct mapping of the existing ioctl commands the following description uses that.
+
+The CAIF Kernel Driver will act on the given \b CREATE or \b DELETE commands and create or delete CAIF channels accordingly.
+
+The hardware drivers for the physical links to the modems is configured by \b ACTIVATE or \b DEACTIVATE commands.
+CAIF PHY Drivers and Channel configuration must be done before any CAIF Channels can be accessed from Linux User Space.
+
+\section Defined commands
+The following commands are defined:
+- \b CREATE                      - Create a new Net or Character device.
+- \b DELETE                      - Delete a Net or Character device
+- \b ACTIVATE                    - Activate a CAIF PHY interface.
+- \b DEACTIVATE                  - De-activate a CAIF PHY interface.
+
+\remark
+Character type devices will show up in /dev/ once they are configured.
+Note also that configured channels are not opened before a file handle is opened from user space.
+
+\section Examples
+The examples below uses the chardevconfig utility as an example on creating channels
+
+\subsection Configuration of an AT type Channel:
+\code
+$ echo "CREATE TYPE=AT DEV=CHAR NAME=chnlat1" | chrdevconfig /dev/caifconfig
+$ ls /dev/chnlat1
+/dev/chnlat1
+\endcode
+
+\subsection Example configuration of an RFM type Channel:
+\code
+$ echo "CREATE TYPE=RFM DEV=CHAR NAME=rfm01 CONNID=1 VOLUME=/rfm" | chrdevconfig  /dev/caifconfig
+\endcode
+
+\subsection Configure a new PHY Instance
+\code
+$ echo "CONFIG-PHY TYPE=MSL NAME=PHYMSL8 INSTANCE=1 CHECKSUM=no HEAD-ALIGN=2 TAIL-ALIGN=2 TRANSFER-ALIGN=16
+\endcode
+
+\subsection Example of Android Init file:
+config file, typically /etc/create_devices.config
+\code
+CREATE TYPE=AT NAME=chnlat10 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
+CREATE TYPE=AT NAME=chnlat11 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
+CREATE TYPE=UTIL NAME=chn_psocktest DEVTYPE=CHAR PHYPREF=LAT SOCK=CAIF_PSOCK_TEST PARAM=01
+CREATE TYPE=DGMLOOP NAME=datagram_loop DEVTYPE=CHAR PHYPREF=BW
+\endcode
+and the init entry would be:
+\code
+# init file entry for CAIF
+# Configure MSL for CAIF
+chardevconfig /dev/caifconfig /etc/create_devices.config
+\endcode
+
+
+\section Configuration syntax
+
+\code
+CREATE					Create new CAIF Channel
+TYPE=[ AT | UTIL | DGM | RFM | DEBUG ]	Type of CAIF Channel to configure.
+NAME=<devname>				Name of character device to create. Device will be visible in /dev/<devname>.
+DEVTYPE=CHAR | NET			Type of Linux Device to create, Character Device or Net Device.
+PHYNAME=<name> | PHYPEF= BW | LAT	Name of Physical Device, or preference Bandwidth (BW) or Latency (LAT)
+[ PRIO=[ HI, NORM, LOW ] ]		Priority level payload data in the CAIF Channel.
+[ CONNID=<id> ]			Connection ID - Applies to RFM and DATAGRAM
+[ VOLUME=<volume> ] 			Volume name of RFM, Applies to RFM only
+[ SOCK=<PSOCK NAME> ] 			PSock Server Name, Applies to PSOCK only
+[ PARAM=<param> ] 			Parameter to PSOCK, Applies to PSOCK only
+
+
+DELETE NAME=<devname>			Deletes a CAIF Channel
+
+
+ACTIVATE				Activates a new CAIF PHY Instance
+PHYTYPE=[UART|SPI|MSL|SHM|LOOP]	Type of CAIF PHY Instance to configure
+NAME=<phy-name>			Name of the CAIF PHY Device
+INSTANCE=<id>				Instance ID of the device
+CHECKSUM=[yes|no]			Frame Checksum is used for this PHY
+PARAM=...				Other PHY Specific configuration parameters
+
+
+DEACTIVATE NAME=<phy-name>		De-activates a PHY Instance
+
+\endcode
+*/
diff --git a/Documentation/CAIF/chardevconfig/Makefile b/Documentation/CAIF/chardevconfig/Makefile
new file mode 100644
index 0000000..5bd7d90
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/Makefile
@@ -0,0 +1,11 @@
+CFLAGS=-g -Wall -I ../../../include -I../../../include/linux/caif
+
+PROGS=chardevconfig
+OBJS=chardevconfig.o caif_cmd_parse.o
+all: $(PROGS)
+
+chardevconfig: chardevconfig.o caif_cmd_parse.o
+	$(CC) $(CFLAGS) -o chardevconfig $(OBJS)
+
+clean:
+	rm -f $(PROGS) $(OBJS)
diff --git a/Documentation/CAIF/chardevconfig/README b/Documentation/CAIF/chardevconfig/README
new file mode 100644
index 0000000..bc7013b
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/README
@@ -0,0 +1,39 @@
+Usage: chardevconfig configdevice configfile
+Usage: chardevconfig configdevice -
+
+The program will read commands from the configfile (or stdin), parse them and
+do ioctl calls to the configdevice. One command per line. Lines with syntax
+errors (e.g. starting with a #) will be skipped.
+
+Examples:
+
+CREATE TYPE=AT NAME=chnlat10 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
+CREATE TYPE=AT NAME=chnlat11 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
+CREATE TYPE=AT NAME=chnlat12 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
+CREATE TYPE=AT NAME=chnlat13 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
+
+CREATE TYPE=RFM NAME=chn_rfm DEVTYPE=CHAR PHYPREF=BW CONNID=1 VOLUME=rfm
+CREATE TYPE=RFM NAME=chn_afs DEVTYPE=CHAR PHYPREF=BW CONNID=1 VOLUME=/afs
+CREATE TYPE=RFM NAME=chn_ifs DEVTYPE=CHAR PHYPREF=BW CONNID=1 VOLUME=/ifs
+CREATE TYPE=RFM NAME=chn_sys DEVTYPE=CHAR PHYPREF=BW CONNID=1 VOLUME=/sys"
+
+CREATE TYPE=UTIL NAME=chn_psocktest DEVTYPE=CHAR PHYPREF=LAT SOCK=CAIF_PSOC_TEST PARAM=01
+
+CREATE TYPE=DGM NAME=chn_datagram DEVTYPE=CHAR PHYPREF=BW CONNID=1
+CREATE TYPE=DGM NAME=datagram_raw_ip DEVTYPE=CHAR PHYPREF=BW CONNID=1
+
+CREATE TYPE=DGMLOOP NAME=datagram_loop DEVTYPE=CHAR PHYPREF=BW
+
+
+DELETE NAME=chnlat10 DEVTYPE=CHAR
+DELETE NAME=chnlat11 DEVTYPE=CHAR
+DELETE NAME=chnlat12 DEVTYPE=CHAR
+DELETE NAME=chnlat13 DEVTYPE=CHAR
+DELETE NAME=chn_rfm DEVTYPE=CHAR
+DELETE NAME=chn_afs DEVTYPE=CHAR
+DELETE NAME=chn_ifs DEVTYPE=CHAR
+DELETE NAME=chn_sys DEVTYPE=CHAR
+DELETE NAME=chn_psocktest DEVTYPE=CHAR
+DELETE NAME=chn_datagram DEVTYPE=CHAR
+DELETE NAME=datagram_loop DEVTYPE=CHAR
+DELETE NAME=datagram_raw_ip DEVTYPE=CHAR
diff --git a/Documentation/CAIF/chardevconfig/caif_cmd_parse.c b/Documentation/CAIF/chardevconfig/caif_cmd_parse.c
new file mode 100644
index 0000000..0833184
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/caif_cmd_parse.c
@@ -0,0 +1,366 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/ioctl.h>
+#include <caif_config.h>
+#include <caif_ioctl.h>
+#include <stdio.h>
+
+#define CFLOG_TRACE(a)
+
+
+/** Strips of blanks */
+void skip_blanks(char **c)
+{
+	while (**c == ' ')
+		(*c)++;
+
+}
+
+/** Parses the specified command.
+ *  @param[in/out] in Pointer to where to start parsing, and if parsing successfull position behind parsed tex
+ *  @param[in]     cmd String to parse
+ *  @return        1 on success, 0 on error
+ */
+int cmd_parse(char **in, char *cmd, int *err)
+{
+
+	char *pos = *in;
+	skip_blanks(&pos);
+	if (strncmp(pos, cmd, strlen(cmd)) == 0) {
+		pos += strlen(cmd);
+		skip_blanks(&pos);
+		*in = pos;
+		CFLOG_TRACE(("arg_parse: Match '%s'\n", cmd));
+
+		return 1;
+	}
+	return 0;
+}
+
+/** Parses a value pair on the format <CMD> = <arg>
+ *  @param[in/out] in Pointer to where to start parsing, and if parsing successfull position behind parsed tex
+ *  @param[in]     cmd String to parse
+ *  @param[out]    arg Argument on the right side of '='
+ *  @return        1 on success, 0 on error
+ */
+int arg_parse(char **in, char *cmd, char *arg, int arglen, int *err)
+{
+	char *pos = *in;
+	skip_blanks(&pos);
+	if (strncmp(pos, cmd, strlen(cmd)) == 0) {
+		pos += strlen(cmd);
+		skip_blanks(&pos);
+		if (*pos != '=') {
+			*err = 1;
+			return 0;
+		}
+		pos++;
+		while (*pos && *pos != ' ')
+			*arg++ = *pos++;
+		*arg = 0;
+		skip_blanks(&pos);
+		*in = pos;
+		CFLOG_TRACE(("arg_parse: Match '%s' Arg: '%s'\n", cmd, pos));
+		return 1;
+	}
+	return 0;
+}
+
+/** Parses a value pair on the format <CMD> = <int>
+ *  @param[in/out] in Pointer to where to start parsing, and if parsing successfull position behind parsed tex
+ *  @param[in]     cmd
+ *  @param[out]    val Parsed integer value
+ *  @return        1 on success, 0 on error
+ */
+int int_parse(char **in, char *cmd, int *val, int *err)
+{
+	char *pos = *in;
+	char arg[100];
+	if (arg_parse(&pos, cmd, arg, sizeof(arg), err)) {
+		sscanf(arg, "%d", val);
+		*in = pos;
+		CFLOG_TRACE(("int_parse: Match '%s' '%d'\n", cmd, *val));
+
+		return 1;
+	}
+	return 0;
+}
+
+/** Parses a value pair on the format <CMD> = <hex-string>
+ *  @param[in/out] in     Pointer to where to start parsing, and if parsing successfull position behind parsed tex
+ *  @param[in]     cmd    Integer to parse
+ *  @param[out]    tobuf  Parsed hex string
+ *  @param[in]     maxlen Max-len of the binary parsed hex string
+ *  @param[out]    buflen Length of the parsed hex sting (in bytes)
+ *  @return        1 on success, 0 on error
+ */
+
+int
+hex_parse(char **in, char *cmd, unsigned char *tobuf, int maxlen,
+	  int *buflen, int *err)
+{
+	char *pos = *in;
+	char tmp[3];
+	int start = maxlen - 1;
+	int val = 0;
+	int len = 0;
+	int i;
+	char hexstr[100];
+	unsigned char buf[256];
+	if (arg_parse(&pos, cmd, hexstr, sizeof(hexstr), err)) {
+
+		i = strlen(hexstr);
+		while (i > 0) {
+			tmp[0] = hexstr[i - 2];
+			tmp[1] = hexstr[i - 1];
+			tmp[2] = 0;
+			sscanf(tmp, "%x", &val);
+			buf[start--] = (unsigned char) (val & 0xff);
+			len++;
+			i -= 2;
+		}
+		*buflen = len;
+		for (i = 0; i < len; i++)
+			tobuf[i] = buf[maxlen - len + i];
+
+		*in = pos;
+		CFLOG_TRACE(("hex_parse: Match '%s' '%s'\n", cmd, tmp));
+		return 1;
+	}
+	return 0;
+}
+
+/** Parses a value pair on the format <CMD> = <token>
+ *  @param[in/out] in      Pointer to where to start parsing, and if parsing successfull position behind parsed tex
+ *  @param[in]     cmd     Integer to parse
+ *  @param[out]    toktype Specify the class of tokens to be parsed
+ *  @param[in]     val     Specify the value (in enums) corresponding to a token
+ *  @return        1 on success, 0 on error
+ */
+
+int tok_parse(char **in, char *cmd, char *toktype, int *val, int *err)
+{
+	struct {
+		char *tok;
+		char *toktype;
+		int val;
+	} tokens[] = {
+		{
+		"LAT", "PHYPREF", CAIF_PHYPREF_LOW_LAT}, {
+		"BW", "PHYPREF", CAIF_PHYPREF_HIGH_BW}, {
+		"LOOP", "PHYPREF", _CAIF_PHYPREF_LOOP}, {
+		"LOW", "PRIO", CAIF_PRIO_LOW}, {
+		"NORM", "PRIO", CAIF_PRIO_NORMAL}, {
+		"HI", "PRIO", CAIF_PRIO_HIGH}, {
+		"AT", "CHTY", CAIF_CHTY_AT}, {
+		"DGM", "CHTY", CAIF_CHTY_DATAGRAM}, {
+		"DGMLOOP", "CHTY", CAIF_CHTY_DATAGRAM_LOOP}, {
+		"VIDEO", "CHTY", CAIF_CHTY_VIDEO}, {
+		"DEBUG", "CHTY", CAIF_CHTY_DEBUG}, {
+		"TRACE", "CHTY", CAIF_CHTY_DEBUG_TRACE}, {
+		"IDEBUG", "CHTY", CAIF_CHTY_DEBUG_INTERACT}, {
+		"RFM", "CHTY", CAIF_CHTY_RFM}, {
+		"UTIL", "CHTY", CAIF_CHTY_UTILITY}, {
+		"YES", "BOOL", 1}, {
+		"NO", "BOOL", 0}, {
+		"CHAR", "DEVTY", CAIF_DEV_CHR}, {
+		"NET", "DEVTY", CAIF_DEV_NET}, {
+
+		NULL, 0}
+	};
+
+	char tok[100];
+	char *pos = *in;
+
+	if (arg_parse(&pos, cmd, tok, sizeof(tok), err)) {
+		int i;
+		for (i = 0; tokens[i].tok != NULL; i++) {
+			if (strcmp(tokens[i].toktype, toktype) == 0
+			    && strcmp(tokens[i].tok, tok) == 0) {
+
+				*val = tokens[i].val;
+				*in = pos;
+				CFLOG_TRACE(("tok_parse:"
+					     " Match '%s' '%s' (%s)->%d\n",
+					     cmd, tok, toktype, *val));
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/** Parses a command string from user.
+ *  @param[in]     cmd     The command string to be parsed
+ *  @param[out]    action  The type of action of this string
+ *  @param[in]     param   The action parameters for this command
+ *  @return        0 on success, < 0 on error.
+ */
+int caif_cmd_parse(char *cmd, int *action, union caif_action *param)
+{
+
+	int err = 0;
+	char *pos = cmd;
+	int val;
+	int len;
+	unsigned char *u;
+	int phy_specified = 0;
+	memset(param, 0, sizeof(*param));
+	if (cmd_parse(&pos, "HELP", &err))
+		return 0;
+
+	if (cmd_parse(&pos, "DELETE", &err)) {
+		struct caif_device_name *cf = &param->delete_channel;
+		*action = CAIF_IOC_REMOVE_DEVICE;
+
+		CFLOG_TRACE(("DELETE -  pos='%s'\n", pos));
+
+		if (arg_parse(&pos, "NAME", cf->name, sizeof(cf->name), &err)) {
+			CFLOG_TRACE(("NAME - arg='%s' pos='%s'\n", cf->name,
+				     pos));
+
+		} else {
+			CFLOG_TRACE(("Parse Error for DELETE: '%s'\n", pos));
+			return -1;
+		}
+
+		if (tok_parse(&pos, "DEVTYPE", "DEVTY", &val, &err)) {
+			cf->devtype = val;
+			CFLOG_TRACE(("DEVTYPE - arg='%d' pos='%s'\n", val,
+				     pos));
+
+		} else {
+			CFLOG_TRACE(("DEVTYPE REQUIRED\n"));
+			return -1;
+		}
+
+
+		if (strlen(pos) > 0) {
+			CFLOG_TRACE(("Could not parse string '%s'\n", pos));
+			return -1;
+		}
+	} else if (cmd_parse(&pos, "CREATE", &err)) {
+		struct caif_channel_create_action *cf = &param->create_channel;
+		*action = CAIF_IOC_CONFIG_DEVICE;
+		CFLOG_TRACE(("CREATE -  pos='%s'\n", pos));
+
+
+		if (tok_parse(&pos, "TYPE", "CHTY", &val, &err)) {
+			cf->config.type = val;
+			CFLOG_TRACE(("TYPE - arg='%d' pos='%s'\n", val, pos));
+
+		} else {
+			CFLOG_TRACE(("TYPE REQUIRED\n"));
+			return -1;
+		}
+
+		if (arg_parse
+		    (&pos, "NAME", cf->name.name, sizeof(cf->name.name),
+		     &err)) {
+			CFLOG_TRACE(("NAME - arg='%s' pos='%s'\n",
+				     cf->name.name, pos));
+
+		} else {
+			CFLOG_TRACE(("NAME REQUIRED\n"));
+			return -1;
+		}
+
+		if (tok_parse(&pos, "DEVTYPE", "DEVTY", &val, &err)) {
+			cf->name.devtype = val;
+			CFLOG_TRACE(("DEVTYPE - arg='%d' pos='%s'\n", val,
+				     pos));
+
+		} else {
+			CFLOG_TRACE(("DEVTYPE REQUIRED\n"));
+			return -1;
+		}
+
+
+		if (arg_parse(&pos, "PHYNAME", cf->config.phy_name,
+			      sizeof(cf->config.phy_name), &err)) {
+			phy_specified = 1;
+			CFLOG_TRACE(("PHYNAME - arg='%s' pos='%s'\n",
+				     cf->config.phy_name, pos));
+
+		}
+		if (tok_parse(&pos, "PHYPREF", "PHYPREF", &val, &err)) {
+			cf->config.phy_pref = val;
+			phy_specified = 1;
+			CFLOG_TRACE(("NAME - val='%d' pos='%s'\n", val, pos));
+
+		}
+
+		if (!phy_specified) {
+			CFLOG_TRACE(("PHYNAME or PHYPREF REQUIRED\n"));
+			return -1;
+		}
+
+		if (tok_parse(&pos, "PRIO", "PRIO", &val, &err)) {
+			cf->config.priority = val;
+			CFLOG_TRACE(("PRIO - val='%d' pos='%s'\n", val, pos));
+
+		}
+		if (cf->config.type == CAIF_CHTY_DATAGRAM
+		    && int_parse(&pos, "CONNID", &val, &err)) {
+			cf->config.u.dgm.connection_id = val;
+			CFLOG_TRACE(("CONNID - val='%d' pos='%s'\n", val,
+				     pos));
+
+		}
+		if (cf->config.type == CAIF_CHTY_RFM
+		    && int_parse(&pos, "CONNID", &val, &err)) {
+			cf->config.u.rfm.connection_id = val;
+			CFLOG_TRACE(("CONNID - val=%d pos='%s'\n", val, pos));
+
+		}
+		if (cf->config.type == CAIF_CHTY_RFM
+		    && arg_parse(&pos, "VOLUME", cf->config.u.rfm.volume,
+				 sizeof(cf->config.u.rfm.volume), &err)) {
+			cf->config.u.rfm.connection_id = val;
+			CFLOG_TRACE(("VOLUME - arg='%s' pos='%s'\n",
+				     cf->config.u.rfm.volume, pos));
+
+		}
+		if (cf->config.type == CAIF_CHTY_UTILITY
+		    && arg_parse(&pos, "SOCK", cf->config.u.utility.name,
+				 sizeof(cf->config.u.utility.name), &err)) {
+			cf->config.u.rfm.connection_id = val;
+			CFLOG_TRACE(("SOCK - arg='%s' pos='%s'\n",
+				     cf->config.u.utility.name, pos));
+
+		}
+
+		if (cf->config.type == CAIF_CHTY_UTILITY
+		    && hex_parse(&pos, "PARAM",
+				 cf->config.u.utility.params,
+				 sizeof(cf->config.u.utility.params), &len,
+				 &err)) {
+			cf->config.u.utility.paramlen = len;
+			u = cf->config.u.utility.params;
+			CFLOG_TRACE(("PARAM %02x,%02x,%02x,%02x-  pos='%s'\n",
+				     u[0], u[1], u[2], u[3], pos));
+
+		}
+
+		if (strlen(pos) > 0) {
+			CFLOG_TRACE(("Could not parse string '%s'\n", pos));
+			return -1;
+		}
+
+	} else {
+		CFLOG_TRACE(("UNRECOGNIZED COMMAND '%s'\n", pos));
+		return -1;
+	}
+	return 0;
+
+}
diff --git a/Documentation/CAIF/chardevconfig/caif_cmd_parse.h b/Documentation/CAIF/chardevconfig/caif_cmd_parse.h
new file mode 100644
index 0000000..d27227f
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/caif_cmd_parse.h
@@ -0,0 +1,22 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+
+#ifndef CAIF_CMD_PARSE_H_
+#define CAIF_CMD_PARSE_H_
+
+#include "caif_config.h"
+#include "caif_ioctl.h"
+
+int caif_cmd_parse(char *cmd, int *action, union caif_action *param);
+
+#endif
diff --git a/Documentation/CAIF/chardevconfig/chardevconfig.c b/Documentation/CAIF/chardevconfig/chardevconfig.c
new file mode 100644
index 0000000..2aee860
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/chardevconfig.c
@@ -0,0 +1,110 @@
+/*
+ *      Copyright (C) ST-Ericsson AB 2009
+ *
+ *      Author: Per Sigmond / Per.Sigmond@stericsson.com
+ *
+ *      License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <caif_ioctl.h>
+#include "caif_cmd_parse.h"
+
+
+#define BUFFERLENGTH 512
+
+
+void usage(char *argv0)
+{
+	fprintf(stderr, "Usage: %s device configfile\n", argv0);
+	fprintf(stderr, "Usage: %s device -\n", argv0);
+}
+
+int main(int argc, char *argv[])
+{
+
+	int fd;
+	FILE *configfile;
+	char *config_devname;
+	union caif_action param;
+	int request;
+	int ret;
+	char *cmd;
+	int bytes_read;
+
+	if (argc < 3) {
+		usage(argv[0]);
+		exit(-1);
+	}
+	config_devname = argv[1];
+
+	if (!strncmp(argv[2], "-", 1)) {
+		/* stdin */
+		configfile = stdin;
+	} else {
+		configfile = fopen(argv[2], "r");
+	}
+	if (configfile == NULL) {
+		fprintf(stderr, "fopen %s: %s\n", argv[2], strerror(errno));
+		exit(-1);
+	}
+
+	cmd = malloc(BUFFERLENGTH);
+	if (cmd == NULL) {
+		fprintf(stderr, "malloc error: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	while (fgets(cmd, BUFFERLENGTH, configfile) != NULL) {
+
+		bytes_read = strlen(cmd);
+		while (isspace(cmd[bytes_read - 1])) {
+			cmd[bytes_read - 1] = 0;
+			bytes_read--;
+		}
+
+		ret = caif_cmd_parse(cmd, &request, &param);
+
+		if (ret != 0) {
+			fprintf(stderr, "'%s'\n", cmd);
+			fprintf(stderr, "Error parsing config string.\n");
+			continue;
+		}
+
+		fd = open(config_devname, O_RDWR);
+		if (fd < 0) {
+			fprintf(stderr, "open %s: %s\n", config_devname,
+				strerror(errno));
+			exit(-1);
+		}
+
+		if (ioctl(fd, request, &param) < 0) {
+			fprintf(stderr, "'%s'\n", cmd);
+			fprintf(stderr, "ioctl: %s\n", strerror(errno));
+		}
+		close(fd);
+
+		if (request == CAIF_IOC_CONFIG_DEVICE) {
+			printf
+			    ("Create device: name = %s, "
+			     "major = %d, minor = %d\n",
+			     param.create_channel.name.name,
+			     param.create_channel.major,
+			     param.create_channel.minor);
+		}
+	}
+
+	fclose(configfile);
+	free(cmd);
+
+	return 0;
+}
diff --git a/Documentation/CAIF/chardevconfig/create_devices.config b/Documentation/CAIF/chardevconfig/create_devices.config
new file mode 100644
index 0000000..374ac19
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/create_devices.config
@@ -0,0 +1 @@
+CREATE TYPE=AT NAME=chnlat1 DEVTYPE=CHAR PHYPREF=LAT PRIO=HI
diff --git a/Documentation/CAIF/chardevconfig/delete_devices.config b/Documentation/CAIF/chardevconfig/delete_devices.config
new file mode 100644
index 0000000..e057a85
--- /dev/null
+++ b/Documentation/CAIF/chardevconfig/delete_devices.config
@@ -0,0 +1 @@
+DELETE NAME=chnlat1 DEVTYPE=CHAR
diff --git a/Documentation/CAIF/ldiscd/README b/Documentation/CAIF/ldiscd/README
new file mode 100644
index 0000000..6936225
--- /dev/null
+++ b/Documentation/CAIF/ldiscd/README
@@ -0,0 +1,12 @@
+Building the line discipline:
+
+Open a shell and cd to the caif/app/ldiscd directory:
+
+First set the environment variables:
+$ source  ~/android-repo/build/envsetup.sh
+
+Set the Android TOP directory (~/android-repo on my machine):
+$ export TOP=~/android-repo
+
+Now build (the output will end up in: ~/android-repo/out/target/product/generic/system/bin/ldiscd)
+$ mm
diff --git a/Documentation/CAIF/ldiscd/ldiscd.c b/Documentation/CAIF/ldiscd/ldiscd.c
new file mode 100644
index 0000000..9e3483d
--- /dev/null
+++ b/Documentation/CAIF/ldiscd/ldiscd.c
@@ -0,0 +1,123 @@
+/*
+ *	Copyright (C) ST-Ericsson AB 2009
+ *
+ *	Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+
+
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <termios.h>
+#include <asm/ioctls.h>
+
+#define CAIF_LDISC_TTY	"/dev/ttyS0"
+
+int main(void)
+{
+
+	/* Our process ID and Session ID */
+	pid_t pid, sid;
+
+	/* Termios structure for UART configuration. */
+	struct termios tio;
+
+	/* File handle to the tty device node */
+	int fd;
+
+	/* Result */
+	int result;
+
+	/* Line discipline number to use (N_MOUSE) */
+	int ldiscnr = 2;
+
+	/* Fork off the parent process */
+	pid = fork();
+	if (pid < 0)
+		exit(EXIT_FAILURE);
+
+	/* If we got a good PID, then
+	   we can exit the parent process. */
+	if (pid > 0)
+		exit(EXIT_SUCCESS);
+
+
+	/* Change the file mode mask */
+	umask(0);
+
+	/* Open any logs here */
+
+	/* Create a new SID for the child process */
+	sid = setsid();
+	if (sid < 0)
+		/* Log the failure */
+		exit(EXIT_FAILURE);
+
+
+	/* Change the current working directory */
+	if ((chdir("/")) < 0)
+		/* Log the failure */
+		exit(EXIT_FAILURE);
+
+
+	/* Close out the standard file descriptors */
+	close(STDIN_FILENO);
+	close(STDOUT_FILENO);
+	close(STDERR_FILENO);
+
+	/* Daemon-specific initialization goes here */
+
+	/* Open the tty device node */
+	fd = open(CAIF_LDISC_TTY, O_RDWR);
+	if (fd < 0) {
+		/* Log the failure */
+		exit(EXIT_FAILURE);
+	}
+
+	/* Configure UART settings. */
+	memset(&tio, 0, sizeof(tio));
+
+	/* 115200 baud, 8n1, CTS/RTS flow control. */
+	tio.c_cflag = B115200 | CRTSCTS | CS8 | CLOCAL | CREAD;
+
+	/* Flush TTY and set new termios. */
+	result = tcflush(fd, TCIOFLUSH);
+	if (result)
+		/* Log the failure */
+		exit(EXIT_FAILURE);
+
+
+	result = tcsetattr(fd, TCSANOW, &tio);
+	if (result)
+		/* Log the failure */
+		exit(EXIT_FAILURE);
+
+
+	/* Change line discipline for the tty device and keep it open */
+	result = ioctl(fd, TIOCSETD, &ldiscnr);
+	if (result < 0)
+		/* Log the failure */
+		exit(EXIT_FAILURE);
+
+
+	/* The Big Loop */
+	while (1)
+		sleep(0x7FFFFFFF);
+
+
+	close(fd);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/Documentation/DocBook/caif.tmpl b/Documentation/DocBook/caif.tmpl
new file mode 100644
index 0000000..23ba098
--- /dev/null
+++ b/Documentation/DocBook/caif.tmpl
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPEbook PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"[]>
+
+<book id="GuidtoCAIF">
+<bookinfo>
+<title>CAIF Programming Guide</title>
+
+<authorgroup>
+<author>
+<firstname>Sjur</firstname>
+<surname>Brendeland/</surname>
+<affiliation>
+<address>
+<email>sjur.brandeland@stericsson.com</email>
+</address>
+</affiliation>
+</author>
+</authorgroup>
+
+<copyright>
+<year>2009</year>
+<holder>ST-Ericsson AB</holder>
+</copyright>
+
+<legalnotice>
+<para>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later
+version.
+</para>
+
+<para>
+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.
+</para>
+
+<para>
+You should have received a copy of the GNU General Public
+License along with this program; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+</para>
+
+<para>
+For more details see the file COPYING in the source
+distribution of Linux.
+</para>
+</legalnotice>
+</bookinfo>
+
+<toc></toc>
+
+<chapter id="intro">
+<title>Introduction</title>
+<para>
+
+
+ !!!!!!! WARNING this document is a work in progrss and is not
+ !!!!!!! complete or accurate at this point in time
+
+
+CAIF is a MUX protocol used by ST-Ericsson cellular modems for
+communication
+between Modem and host. The host processes can open virtual AT
+channels, initiate GPRS Data connections, Video channels and
+Utility Channels.
+The Utility Channels are general purpose pipes between modem
+and host.
+
+ST-Ericsson modems support a number of transports between modem
+and host,
+currently Uart and Shared Memory are available for Linux.
+
+</para>
+
+ <sect1 id="architecture">
+            <title>Architecture</title>
+<para>
+The Implementation of CAIF is divided into:
+<itemizedlist>
+  <listitem> CAIF Drivers: Character Device, Net Device and Kernel API.</listitem>
+  <listitem>CAIF Generic Protocol Implementation</listitem>
+  <listitem>CAIF Link Layer</listitem>
+</itemizedlist>
+</para>
+<para>
+CAIF is using IOCTLs to manage the CAIF Drivers.
+<programlisting>
+  IOCTL
+   !
+   !     +------+   +------+   +------+
+   !    +------+!  +------+!  +------+!
+   !    ! Char !!  !Kernel!!  ! Net  !!
+   !    ! Dev  !+  ! API  !+  ! Dev  !+   <- CAIF Drivers
+   !    +------+   +------!   +------+
+   !       !          !          !
+   !       +----------!----------+
+   !               +------+               <- CAIF Protocol Implementation
+   +------->       ! CAIF !                  /dev/caifconfig
+                   +------+
+             +--------!--------+
+             !                 !
+          +------+          +-----+
+          !ShMem !          ! TTY !       <- Link Layer
+          +------+          +-----+
+</programlisting>
+</para>
+</sect1>
+
+
+</chapter>
+
+<chapter id="bugs">
+<title>Known Bugs And Assumptions</title>
+<para>
+<variablelist>
+
+<varlistentry><term>CAIF is minimal</term>
+<listitem>
+<para>
+	Thecurrent CAIF implementation is very basic
+</para>
+</listitem></varlistentry>
+
+<varlistentry><term>Quirks</term>
+<listitem>
+<para>
+	listquirks here
+</para>
+</listitem></varlistentry>
+</variablelist>
+
+</para>
+</chapter>
+
+<chapter id="config">
+<title>Public Functions Provided</title>
+
+  <para>
+   caif_config.h
+   This file defines the types needed for channel configuration.
+   The CAIF Channel configuration is held in the structure \ref
+   caif_channel_config .
+   The configured character devices will be visible in /dev/caifXXXX.
+  </para>
+
+
+    <para>
+      Example AT channel configuration
+      <programlisting>
+struct caif_channel_config at_config = {
+	.channel	= CAIF_CHTY_AT,
+	.phy_ref	= CAIF_PHYPREF_LOW_LAT,
+	.priority	= CAIF_PRIO_HIGH
+};
+      </programlisting>
+      </para>
+
+      <para>
+        Example Datagram channel configuration
+	<programlisting>
+struct caif_channel_config dgm_config = {
+	.channel		= CAIF_CHTY_DATAGRAM,
+	.phy_ref		= CAIF_PHYPREF_HIGH_BW,
+	.priority		= CAIF_PRIO_NORMAL,
+	.u.dgm.connection_id	= my_connection_id
+};
+		</programlisting>
+		</para>
+
+		<para>
+		Example RFM channel configuration
+		<programlisting>
+struct caif_channel_config rfm_config = {
+	.channel		= CAIF_CHTY_RFM,
+	.phy_ref		= CAIF_PHYPREF_LOW_LAT,
+	.priority 		= CAIF_PRIO_HIGH,
+	.u.rfm.connection_id 	= my_connection_id,
+	.u.rfm.name 		= "/rfm"
+};
+		</programlisting>
+		</para>
+
+		<para>
+		Example Utility channel configuration
+		<programlisting>
+struct caif_channel_config rfm_config = {
+	.channel		= CAIF_CHTY_UTILITY,
+	.phy_ref		= CAIF_PHYPREF_LOW_LAT,
+	.priority		= CAIF_PRIO_HIGH,
+	.u.utility.name		= "PSOCK_TEST_PROC",
+	.u.utility.params	= {0x01},
+	.u.utility.paramlen	= 1,
+	.u.utility.fifosize_kb	= 0,Architecture:
+------------
+The Implementation of CAIF is divided into:
+* CAIF Drivers: Character Device, Net Device and Kernel API.
+* CAIF Generic Protocol Implementation
+* CAIF Link Layer
+
+CAIF is using IOCTLs to manage the CAIF Drivers.
+
+
+  IOCTL
+   !
+   !     +------+   +------+   +------+
+   !    +------+!  +------+!  +------+!
+   !    ! Char !!  !Kernel!!  ! Net  !!
+   !    ! Dev  !+  ! API  !+  ! Dev  !+   <- CAIF Drivers
+   !    +------+   +------!   +------+
+   !       !          !          !
+   !       +----------!----------+
+   !               +------+               <- CAIF Protocol Implementation
+   +------->       ! CAIF !                  /dev/caifconfig
+                   +------+
+             +--------!--------+
+             !                 !
+          +------+          +-----+
+          !ShMem !          ! TTY !       <- Link Layer
+          +------+          +-----+
+
+	.u.utility.fifosize_bufs= 0
+};
+		</programlisting>
+		</para>
+
+!Iinclude/linux/caif/caif_config.h
+!Enet/caif/caif_chnlif.c
+
+</chapter>
+
+
+</book>
-- 
1.6.0.4


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

* [PATCH] [CAIF-RFC 8/8-v2] CAIF Protocol Stack
  2009-10-09 13:39             ` [PATCH] [CAIF-RFC 7/8-v2] " sjur.brandeland
@ 2009-10-09 13:39               ` sjur.brandeland
  2009-10-12 13:43               ` [PATCH] [CAIF-RFC 7/8-v2] " Stefano Babic
  1 sibling, 0 replies; 18+ messages in thread
From: sjur.brandeland @ 2009-10-09 13:39 UTC (permalink / raw)
  To: netdev
  Cc: stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson, Kim Lilliestierna,
	sjur.brandeland

From: Kim Lilliestierna <Kim.xx.Lilliestierna@ericsson.com>

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

---
 drivers/net/Makefile |    1 +
 net/Kconfig          |    1 +
 net/Makefile         |    1 +
 3 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7629c90..d8441a8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -255,4 +255,5 @@ obj-$(CONFIG_NETXEN_NIC) += netxen/
 obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
+obj-$(CONFIG_CAIF) += caif/
 
diff --git a/net/Kconfig b/net/Kconfig
index 0210002..51e3eaa 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -253,5 +253,6 @@ endmenu
 
 source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
+source "net/caif/Kconfig"
 
 endif   # if NET

diff --git a/net/Makefile b/net/Makefile
index ba324ae..449dd91 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_NETLABEL)		+= netlabel/
 obj-$(CONFIG_IUCV)		+= iucv/
 obj-$(CONFIG_RFKILL)		+= rfkill/
 obj-$(CONFIG_NET_9P)		+= 9p/
+obj-$(CONFIG_CAIF)		+= caif/
 ifneq ($(CONFIG_DCB),)
 obj-y				+= dcb/
 endif
-- 
1.6.0.4


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

* Re: [PATCH] [CAIF-RFC 5/8-v2] CAIF Protocol Stack
  2009-10-09 13:39         ` [PATCH] [CAIF-RFC 5/8-v2] " sjur.brandeland
  2009-10-09 13:39           ` [PATCH] [CAIF-RFC 6/8-v2] " sjur.brandeland
@ 2009-10-09 16:43           ` Randy Dunlap
  2009-10-12 12:51           ` Stefano Babic
  2 siblings, 0 replies; 18+ messages in thread
From: Randy Dunlap @ 2009-10-09 16:43 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson

On Fri, 09 Oct 2009 15:39:28 +0200 sjur.brandeland@stericsson.com wrote:

> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 
> Change-Id: I205c5b3baf1542e1593637ce896d8684870415be
> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
> ---
>  net/caif/Kconfig            |   61 ++
>  net/caif/Makefile           |   56 ++
>  net/caif/caif_chnlif.c      |  219 +++++++
>  net/caif/caif_chr.c         |  374 ++++++++++++
>  net/caif/caif_config_util.c |  167 ++++++
>  net/caif/chnl_chr.c         | 1393 +++++++++++++++++++++++++++++++++++++++++++
>  net/caif/chnl_net.c         |  492 +++++++++++++++
>  7 files changed, 2762 insertions(+), 0 deletions(-)
>  create mode 100644 net/caif/Kconfig
>  create mode 100644 net/caif/Makefile
>  create mode 100644 net/caif/caif_chnlif.c
>  create mode 100644 net/caif/caif_chr.c
>  create mode 100644 net/caif/caif_config_util.c
>  create mode 100644 net/caif/chnl_chr.c
>  create mode 100644 net/caif/chnl_net.c
> 
> diff --git a/net/caif/Kconfig b/net/caif/Kconfig
> new file mode 100644
> index 0000000..7fb9e9c
> --- /dev/null
> +++ b/net/caif/Kconfig
> @@ -0,0 +1,61 @@
> +#
> +# CAIF net configurations
> +#
> +
> +#menu "Caif Support"
> +comment "CAIF Support"
> +
> +menuconfig CAIF
> +	tristate "Enable Caif support"
> +	default n
> +	---help---
> +	Say Y here if you need to use a phone modem that uses CAIF as transport

	end above with period ('.').

> +	You will also need to say yes to any caif physical devices that your platform
> +	supports.
> +	This can be either built-in or as a loadable module, if you select to build it as module

s/,/;/

> +	the other CAIF also needs to built as modules

	the other CAIF {options or drivers or some other word here} also need  ... modules.
	(end with period)


> +	See Documentation/CAIF for a further explanation on how to use and configure.
> +
> +if CAIF
> +
> +config CAIF_CHARDEV
> +	tristate "CAIF character device"
> +	default CAIF
> +	---help---
> +	Say Y if you will be using the CAIF AT type character devices.
> +	This can be either built-in or as a loadable module,
> +	If you select to build it as a built in then the main caif device must also be a builtin.
> +	If unsure say Y.
> +
> +config CAIF_NETDEV
> +	tristate "CAIF Network device"
> +	default CAIF
> +	---help---
> +	Say Y if you will be using the CAIF based network device.
> +	This can be either built-in or as a loadable module,
> +	If you select to build it as a built in then the main caif device must also be a builtin.
> +	If unsure say Y.
> +
> +
> +config  CAIF_USE_PLAIN
> +	bool  "Use plain buffers instead of SKB in caif"
> +	default n
> +	---help---
> +	Use plain buffer to transport data,

	s/,/./

> +	Select what type of internal buffering CAIF should use,
> +	skb or plain.
> +	If unsure say N hre.
> +
> +config  CAIF_DEBUG
> +	bool "Enable Debug"
> +	default n
> +	--- help ---
> +	Enable the inclusion of debug code in the caif stack,
> +	be aware that doing this will impact performance.
> +	If unsure say N here.
> +
> +# Include physical drivers
> +# source "drivers/net/caif/Kconfig"

Drop the above line.

> +source "drivers/net/caif/Kconfig"
> +endif
> +#endmenu


---
~Randy

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

* Re: [PATCH] [CAIF-RFC 1/8-v2] CAIF Protocol Stack
  2009-10-09 13:39 ` [PATCH] [CAIF-RFC 1/8-v2] " sjur.brandeland
  2009-10-09 13:39   ` [PATCH] [CAIF-RFC 2/8-v2] " sjur.brandeland
@ 2009-10-12  8:08   ` Stefano Babic
  2009-10-12  8:20     ` David Miller
  1 sibling, 1 reply; 18+ messages in thread
From: Stefano Babic @ 2009-10-12  8:08 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 
> Change-Id: I305056f116a11c31265f65ac0fe285e2b655dd54
> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
> ---
>  include/linux/caif/caif_config.h |  203 ++++++++++++++++++++++++++++++++++++++
>  include/linux/caif/caif_ioctl.h  |  113 +++++++++++++++++++++
>  2 files changed, 316 insertions(+), 0 deletions(-)
>  create mode 100644 include/linux/caif/caif_config.h
>  create mode 100644 include/linux/caif/caif_ioctl.h
> 
> diff --git a/include/linux/caif/caif_config.h b/include/linux/caif/caif_config.h
> new file mode 100644
> index 0000000..6ea934b
> --- /dev/null
> +++ b/include/linux/caif/caif_config.h
> @@ -0,0 +1,203 @@
> +/*
> + *	Copyright (C) ST-Ericsson AB 2009
> + *
> + *	CAIF Channel Configuration definitions.
> + *
> + *	Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
> + *
> + *	License terms: GNU General Public License (GPL), version 2.

In the majority of linux drivers we find the following statements to set
up the license terms :

 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

> + * \b Documentation see STE Doc No: 155 19-CRH 109 913.

Probably you should remove this line as you already did in other places.

> diff --git a/include/linux/caif/caif_ioctl.h b/include/linux/caif/caif_ioctl.h

> +/* Use 'g' as magic number. 'g' is the first free letter in
> + * Documentation/ioctl-number.txt*/

The file is Documentation/ioctl/ioctl-number.txt

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

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

* Re: [PATCH] [CAIF-RFC 1/8-v2] CAIF Protocol Stack
  2009-10-12  8:08   ` [PATCH] [CAIF-RFC 1/8-v2] " Stefano Babic
@ 2009-10-12  8:20     ` David Miller
  0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2009-10-12  8:20 UTC (permalink / raw)
  To: stefano.babic
  Cc: sjur.brandeland, netdev, kim.xx.lilliestierna, christian.bejram,
	daniel.martensson

From: Stefano Babic <stefano.babic@babic.homelinux.org>
Date: Mon, 12 Oct 2009 10:08:36 +0200

> sjur.brandeland@stericsson.com wrote:
>> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
>> @@ -0,0 +1,203 @@
>> +/*
>> + *	Copyright (C) ST-Ericsson AB 2009
>> + *
>> + *	CAIF Channel Configuration definitions.
>> + *
>> + *	Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
>> + *
>> + *	License terms: GNU General Public License (GPL), version 2.
> 
> In the majority of linux drivers we find the following statements to set
> up the license terms :
> 
>  * This program is free software; you can redistribute it and/or modify
>  * it under the terms of the GNU General Public License as published by
>  * the Free Software Foundation; either version 2 of the License, or
>  * (at your option) any later version.

But Linus has stated explicitly that Linux itself falls under
GPL v2 and only v2.

See COPYING at the top level of the kernel sources.

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

* Re: [PATCH] [CAIF-RFC 2/8-v2] CAIF Protocol Stack
  2009-10-09 13:39   ` [PATCH] [CAIF-RFC 2/8-v2] " sjur.brandeland
  2009-10-09 13:39     ` [PATCH] [CAIF-RFC 3/8-v2] " sjur.brandeland
@ 2009-10-12  9:28     ` Stefano Babic
  1 sibling, 0 replies; 18+ messages in thread
From: Stefano Babic @ 2009-10-12  9:28 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 

Hi Sjur,

> diff --git a/include/net/caif/generic/cfcnfg.h b/include/net/caif/generic/cfcnfg.h

> +/** Types of Physical Layers defined in CAIF Stack */
> +typedef enum _cfcnfg_phy_type_t {
> +	CFPHYTYPE_UNKNOWN = 0,
> +	CFPHYTYPE_SERIAL = 1,	/*!< Serial Physical Interface */
> +	CFPHYTYPE_SPI = 2,	/*!< SPI Physical Interface */
> +	CFPHYTYPE_MSL = 3,	/*!< MSL Physical Interface */
> +	CFPHYTYPE_SHM = 4,	/*!< Shared Memory Physical Interface */

You actually removed the shared memory driver. Do you plan to insert it
again ?


> +/**
> + * Adds a Adaptation Layer to the CAIF Stack.
> + * The Adaptation Layer is where the interface to application or higher-level
> + * driver functionality is implemented.
> + * \image html AddVeiCaifConfig.jpg "Add an Adaptation layer to CAIF Stack."

There are references to pictures that are not provided.

> diff --git a/include/net/caif/generic/cfglue.h b/include/net/caif/generic/cfglue.h

[snip]

> +/* ASSERT */
> +#define cfglu_assert(exp) BUG_ON(!(exp))

I do not why, but even GENERIC_BUG is not defined for all architectures.
This means that BUG_ON is simply removed by the compiler and we get no
track if the assert fails.
It should be better to add at least an internal trace (adding for
example a CFLOG_FATAL call).

> diff --git a/include/net/caif/generic/cfshml.h b/include/net/caif/generic/cfshml.h

Is thif file probably obsolete ?

> diff --git a/include/net/caif/generic/cfspil.h b/include/net/caif/generic/cfspil.h
> +/** @page SPI PHY Layer description.
> + *
> + *  SPI Physical layer is not implemented in GenCaif. The SPI PHY Layer
> + *  is HW dependent. But the CFSPIL (Caif SPI Layer) provides support for
> + *  implementing the SPI Layer Protocol.

Not sure I have understood. There is an abstraction layer for SPI in
kernel and some generic purpose functions are provided (spy_sync,
spi_async, etc.) that are HW independent. I know they provide only the
methods for the data transfer, but I have imagined that we need at this
point some kind of "caif_spi_device" that is able to talk with the caif
stack on one side and uses the functions in the SPI framework. In any
case, HW independent. Have I missed something ?

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

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

* Re: [PATCH] [CAIF-RFC 0/8-v2] CAIF Protocol Stack
  2009-10-09 13:39 [PATCH] [CAIF-RFC 0/8-v2] CAIF Protocol Stack sjur.brandeland
  2009-10-09 13:39 ` [PATCH] [CAIF-RFC 1/8-v2] " sjur.brandeland
@ 2009-10-12  9:41 ` David Miller
  1 sibling, 0 replies; 18+ messages in thread
From: David Miller @ 2009-10-12  9:41 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, stefano.babic, randy.dunlap, kim.xx.lilliestierna,
	christian.bejram, daniel.martensson

From: sjur.brandeland@stericsson.com
Date: Fri, 09 Oct 2009 15:39:23 +0200

> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 
> This is the second version of the CAIF patch set.
> The patch set is compiled on 386 for 2.6.31.
> All feedback is apreciated.

There is a lot of coding style issues here I'd like you to
address in your next submission.

Comments are formatted in several places like this:

/*
*
*
*/

It should be:

/*
 *
 *
 */

Also often there are tons of extraneous empty lines in the source
files.  Particularly right after the comment at the top of the
source file.  For example include/net/caif/generic/cfcnfg.h
there is the top comment (which needs to be fixed as described
above) and then 8 empty lines before the #ifndef CFCNFG_H_

That's rediculious, just have one empty line there seperating things.

Seriously, you should be able to just scan over your patch and see all
of these oddities.  They jumped right out at me.  Please clean them
up.

Thank you.


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

* Re: [PATCH] [CAIF-RFC 4/8-v2] CAIF Protocol Stack
  2009-10-09 13:39       ` [PATCH] [CAIF-RFC 4/8-v2] " sjur.brandeland
  2009-10-09 13:39         ` [PATCH] [CAIF-RFC 5/8-v2] " sjur.brandeland
@ 2009-10-12 12:20         ` Stefano Babic
  1 sibling, 0 replies; 18+ messages in thread
From: Stefano Babic @ 2009-10-12 12:20 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Hi Sjur,

> 
> diff --git a/net/caif/generic/cfcnfg.c b/net/caif/generic/cfcnfg.c
> new file mode 100644
> index 0000000..3aad201

> + * NOTE: What happends destroy failure:

s/happends/happens/, there are other occurencies.

> +
> +bool cfcnfg_del_adapt_layer(struct _cfcnfg_t *cnfg, layer_t *adap_layer)
> +{
> +	uint8 channel_id = 0;
> +	struct cfcnfg_phyinfo *phyinfo = NULL;
> +	uint8 phyid = 0;
> +	CFLOG_TRACE(("cfcnfg: enter del_adaptation_layer\n"));
> +
> +	cfglu_assert(adap_layer != NULL);
> +	channel_id = adap_layer->id;
> +	cfglu_assert(channel_id != 0);

My two cents about using assert in the code, but I prefer to get some
info from system when something goes wrong as to call in some way panic
(the assert calls BUG_ON) and blocks forever.
This line is not different as checking the adapt_layer->dn pointer some
lines after and I think an error is better recognized in that case. So
IMHO should be better something like:

	if (channel_id == 0) {
		CFLOG_ERROR(("cfcnfg:adap_layer->dn is NULL\n"));
		return CFGLU_EINVAL;
	}


> diff --git a/net/caif/generic/cfpkt_plain.c b/net/caif/generic/cfpkt_plain.c
> +#define CHECK_MEM 1

Probably you plan to use always the magic number in your buffer
management. Then should be better to remove all the #if CHECK_MEM stuff.


> +#if CHECK_MEM
> +
> +#endif

This three lines seem not needed.... ;)

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

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

* Re: [PATCH] [CAIF-RFC 5/8-v2] CAIF Protocol Stack
  2009-10-09 13:39         ` [PATCH] [CAIF-RFC 5/8-v2] " sjur.brandeland
  2009-10-09 13:39           ` [PATCH] [CAIF-RFC 6/8-v2] " sjur.brandeland
  2009-10-09 16:43           ` [PATCH] [CAIF-RFC 5/8-v2] " Randy Dunlap
@ 2009-10-12 12:51           ` Stefano Babic
  2 siblings, 0 replies; 18+ messages in thread
From: Stefano Babic @ 2009-10-12 12:51 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Hi Sjur,

> diff --git a/net/caif/caif_chr.c b/net/caif/caif_chr.c

> +#define caif_assert(assert) BUG_ON(!(assert))

Do we need special assert for each module (cfglu_assert,
caif_assert,...) ? They are all defined in the same way.
At this point I have already set a comment about using BUG_ON in a
previous patch.

I see a mixed policy in this patch, using sometimes _assert and
sometimes directly BUG_ON, too.

> diff --git a/net/caif/chnl_chr.c b/net/caif/chnl_chr.c

> +	/* Lock in order to try to stop someone from opening the device
> +	   too early. The misc device has its own lock. We cannot take our
> +	   lock until misc_register() is finished, because in open() the
> +	   locks are taken in this order (misc first and then dev).
> +	   So anyone managing to open the device between the misc_register
> +	   and the mutex_lock will get a "device not found" error. Don't
> +	   think it can be avoided.
> +	 */
> +	mutex_lock_interruptible(&dev->mutex);

The return value is not checked and it must be, as in all other cases.

> +	/* Find device from name */
> +	dev = find_device(-1, name, 0);
> +	if (!dev)
> +		return -EBADF;
> +
> +

> +	mutex_lock_interruptible(&dev->mutex);

The return value of mutex_lock_interruptible() must be checked.

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

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

* Re: [PATCH] [CAIF-RFC 6/8-v2] CAIF Protocol Stack
  2009-10-09 13:39           ` [PATCH] [CAIF-RFC 6/8-v2] " sjur.brandeland
  2009-10-09 13:39             ` [PATCH] [CAIF-RFC 7/8-v2] " sjur.brandeland
@ 2009-10-12 13:06             ` Stefano Babic
  1 sibling, 0 replies; 18+ messages in thread
From: Stefano Babic @ 2009-10-12 13:06 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>

Hi Sjur,

> +config CAIF_TTY
> +	tristate "CAIF TTY transport driver"
> +	default n
> +	---help---
> +	The CAIF TTY transport driver.
> +	If you say yes here you will also need to build a userspace utility to set the line disicpline on the

s/disicpline/discipline/

> diff --git a/drivers/net/caif/phyif_loop.c b/drivers/net/caif/phyif_loop.c

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

Is there a reason why do you prefer to implement your own ring buffer
management else to use the circ_buf already implemented in kernel ?

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

Specialized assert function for this module, really needed ?

> +
> +	result = tty_register_ldisc(N_MOUSE, &phyif_ldisc);

I think it is time to set up your own discipline include/linux/tty.h,
inserting a N_CAIF line discipline. Reusing other discipline conflicts
with other drivers.

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

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

* Re: [PATCH] [CAIF-RFC 7/8-v2] CAIF Protocol Stack
  2009-10-09 13:39             ` [PATCH] [CAIF-RFC 7/8-v2] " sjur.brandeland
  2009-10-09 13:39               ` [PATCH] [CAIF-RFC 8/8-v2] " sjur.brandeland
@ 2009-10-12 13:43               ` Stefano Babic
  1 sibling, 0 replies; 18+ messages in thread
From: Stefano Babic @ 2009-10-12 13:43 UTC (permalink / raw)
  To: sjur.brandeland
  Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson

sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 

Hi Sjur,

> +ST-Ericsson modems support a number of transports between modem
> +and host,
> +currently Uart and Shared Memory are available for Linux.

Shared Memory was removed in this patchset.

> +== CAIF structure ==
> +
> +The goal is to have caif as system independent as possible.
> +All caif code can be found under GenCaif/src and GenCaif/inc.

The path are wrong, I think you mean net/caif/generic and include/net/caif.

> +The actual linux module implementation is under src/kernel.
> +There is also a user space program that is not up to date to run the stack in
> +user space for testing.

I think you can remove these phrases.

> +
> +We have tested the kernel implementation on the emulator with a modem and we
> +are able to enumerate and make a link setup.

Only as comment: I tested this patchset again on an ARM platform and I
am able to send successfully AT commands to the Ericsson Test Device "B26".

> +      - CFSHML CAIF Shared Memory layer.

Again, this layer was removed and there is no track about SPI Layer.

> +To achieve this we need the help of a daemon program called ldiscd.
> +The benefit is that we can hook up to any TTY, the downside is that we need
> +an extra operation in order to install the line discipline.

I understand the reason, it looks only a quite odd that we need to start
only for this purpose a user space program. And there is no hint if the
daemon is not started, simply caif does not work. What do you think to
set up the line discipline directly in kernel ?

> +Install the line discipline (daemon)
> +$ ldisc



> +
> +Install the VEI channel (this will enumerate and do the linksetup of the first VEI channel. If this goes well you should see /dev/chn*) (There are printks logging all buffers that can be checked with dmesg):
> +$ modprobe chnl_chr
> +
> +The AT (VEI) channel is ready to use (you can now send AT commands on it):

Not really. at this point, the channels are not configured if we do not
use chardevconfig (or we do the same in kernel).

> diff --git a/Documentation/CAIF/caif_user_config.dox b/Documentation/CAIF/caif_user_config.dox

> +The hardware drivers for the physical links to the modems is configured by \b ACTIVATE or \b DEACTIVATE commands.
> +CAIF PHY Drivers and Channel configuration must be done before any CAIF Channels can be accessed from Linux User Space.
> +
> +\section Defined commands
> +The following commands are defined:
> +- \b CREATE                      - Create a new Net or Character device.
> +- \b DELETE                      - Delete a Net or Character device
> +- \b ACTIVATE                    - Activate a CAIF PHY interface.
> +- \b DEACTIVATE                  - De-activate a CAIF PHY interface.

This file seems obsolete. There is no track about ACTIVATE/DEACTIVATE.

> +
> +\remark
> +Character type devices will show up in /dev/ once they are configured.

If you have udev running on your system....

> +Note also that configured channels are not opened before a file handle is opened from user space.
> +
> +\section Examples
> +The examples below uses the chardevconfig utility as an example on creating channels
> +
> +\subsection Configuration of an AT type Channel:
> +\code
> +$ echo "CREATE TYPE=AT DEV=CHAR NAME=chnlat1" | chrdevconfig /dev/caifconfig

This does not work, PHYPREF is missing.


> +$ echo "CREATE TYPE=RFM DEV=CHAR NAME=rfm01 CONNID=1 VOLUME=/rfm" | chrdevconfig  /dev/caifconfig

This does not work, too

> +$ echo "CONFIG-PHY TYPE=MSL NAME=PHYMSL8 INSTANCE=1 CHECKSUM=no HEAD-ALIGN=2 TAIL-ALIGN=2 TRANSFER-ALIGN=16

...and this one does not work.

> +ACTIVATE				Activates a new CAIF PHY Instance
> +PHYTYPE=[UART|SPI|MSL|SHM|LOOP]	Type of CAIF PHY Instance to configure
> +NAME=<phy-name>			Name of the CAIF PHY Device
> +INSTANCE=<id>				Instance ID of the device
> +CHECKSUM=[yes|no]			Frame Checksum is used for this PHY
> +PARAM=...				Other PHY Specific configuration parameters
> +
> +
> +DEACTIVATE NAME=<phy-name>		De-activates a PHY Instance

Not implemented ?


> diff --git a/Documentation/CAIF/ldiscd/ldiscd.c b/Documentation/CAIF/ldiscd/ldiscd.c
> +#define CAIF_LDISC_TTY	"/dev/ttyS0"

I think it should not be bad to avoid a fixed device name and take it as
program parameter.

Stefano

-- 
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE

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

end of thread, other threads:[~2009-10-12 13:43 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-09 13:39 [PATCH] [CAIF-RFC 0/8-v2] CAIF Protocol Stack sjur.brandeland
2009-10-09 13:39 ` [PATCH] [CAIF-RFC 1/8-v2] " sjur.brandeland
2009-10-09 13:39   ` [PATCH] [CAIF-RFC 2/8-v2] " sjur.brandeland
2009-10-09 13:39     ` [PATCH] [CAIF-RFC 3/8-v2] " sjur.brandeland
2009-10-09 13:39       ` [PATCH] [CAIF-RFC 4/8-v2] " sjur.brandeland
2009-10-09 13:39         ` [PATCH] [CAIF-RFC 5/8-v2] " sjur.brandeland
2009-10-09 13:39           ` [PATCH] [CAIF-RFC 6/8-v2] " sjur.brandeland
2009-10-09 13:39             ` [PATCH] [CAIF-RFC 7/8-v2] " sjur.brandeland
2009-10-09 13:39               ` [PATCH] [CAIF-RFC 8/8-v2] " sjur.brandeland
2009-10-12 13:43               ` [PATCH] [CAIF-RFC 7/8-v2] " Stefano Babic
2009-10-12 13:06             ` [PATCH] [CAIF-RFC 6/8-v2] " Stefano Babic
2009-10-09 16:43           ` [PATCH] [CAIF-RFC 5/8-v2] " Randy Dunlap
2009-10-12 12:51           ` Stefano Babic
2009-10-12 12:20         ` [PATCH] [CAIF-RFC 4/8-v2] " Stefano Babic
2009-10-12  9:28     ` [PATCH] [CAIF-RFC 2/8-v2] " Stefano Babic
2009-10-12  8:08   ` [PATCH] [CAIF-RFC 1/8-v2] " Stefano Babic
2009-10-12  8:20     ` David Miller
2009-10-12  9:41 ` [PATCH] [CAIF-RFC 0/8-v2] " David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).