From 189c9bebd36beb1c937f6f66f7b0927798826526 Mon Sep 17 00:00:00 2001
From: Douglas Deao <d-deao@ti.com>
Date: Tue, 8 May 2012 15:14:33 -0500
Subject: [PATCH] STM Framework and OMAP TI1.0 drivers update

- Added binary data transport support
- Added mmap support to map channels back to user space
- Added PID change notification per channel
- Changed "set_header" to "ost_enable" to hide the ost
  implementation within the drivers.
- Modified APIs per feedback from Loic Pallardy:
  config_write - eliminated count parameter
  allocate_channel - changed usecase from char * to enum
- Added patches provided by Loic Pallardy for:
  echo support improvement.
  Modified all cases of "int chn" in the APIs to "void * chn_id".
---
 drivers/stm/Kconfig          |    6 +-
 drivers/stm/stm_fw.c         |  365 +++++++++++++++----------------
 drivers/stm/stm_fw.h         |   22 ++-
 drivers/stm/stm_msg.h        |   13 +-
 drivers/stm/stm_omap_ti1.0.c |  489 +++++++++++++++++++++++++++++++-----------
 5 files changed, 569 insertions(+), 326 deletions(-)

diff --git a/drivers/stm/Kconfig b/drivers/stm/Kconfig
index 1dd648d..a2592ee 100644
--- a/drivers/stm/Kconfig
+++ b/drivers/stm/Kconfig
@@ -5,11 +5,11 @@ config STM_FW
                      STM Framework Driver
 
 config STM_OMAP_TI1_0
-           tristate "STM OMAP TI1.0 Drvier"
+           tristate "STM OMAP TI1.0 Driver"
            depends on STM_FW
            default n
            help
-                     STM OMAP TI1.0 Driver - provides Syet, Trace Macrocell
-		support for V1.0 implementation found in, eg, OMAP4
+                     STM OMAP TI1.0 Driver - provides System Trace Macrocell
+                     support for STM V1.0 implementation found in OMAP4.
 
 
diff --git a/drivers/stm/stm_fw.c b/drivers/stm/stm_fw.c
index e94c7d6..9e415a0 100644
--- a/drivers/stm/stm_fw.c
+++ b/drivers/stm/stm_fw.c
@@ -46,6 +46,8 @@
 #include <linux/ctype.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/version.h>
 
 #include "stm_fw.h"
 #include "stm_msg.h"
@@ -57,19 +59,20 @@
 #define MAX_CONFIG_STRING_BYTES 64
 
 struct stm_chn_descriptor {
-	int chn;		/* Only valid if write_dentry is not NULL */
+	void *chn_id;		/* Only valid if write_dentry is not NULL */
 	bool chn_enable;
 	struct dentry *write_dentry; /* NULL if not a user mode channel */
 	struct dentry *config_dentry; /* Always set for any chan type */
 	bool  write_protect;	   /* Protect writes to the stm channel */
 	struct mutex lock;
-	enum msg_formats msg_format;
-	enum msg_types msg_type;
+	enum msg_format_t msg_format;
+	enum msg_timing_t msg_timing;
 	bool timestamp_enable;
 	bool checksum_enable;
 	bool ost_enable;
-	char ost_entity;
-	char ost_protocol;
+	uint32_t ost_entity;
+	uint32_t ost_protocol;
+	long pid;
 	struct list_head chn_list_link;
 	char chn_filename[MAX_SIZE_FILENAME];
 	char cfg_filename[MAX_SIZE_FILENAME];
@@ -88,7 +91,7 @@ static struct stm_device dev;
 /*****************************************************************************
  * Support function prototypes
  *****************************************************************************/
-static uint8_t cal_checksum(char *buf, int cnt);
+static int8_t cal_checksum(unsigned char *buf, int cnt);
 
 static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor);
 
@@ -96,9 +99,6 @@ static int parse_to_user(char *buf, loff_t buf_pos,
 			  char __user *user_buf, size_t count, loff_t *ppos,
 			  char *delims);
 
-static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
-				    char *kbuf, char *delims);
-
 static int parse_strings_from_string(int num_strings, char *data[],
 						    char *kbuf, char *delims);
 
@@ -122,7 +122,7 @@ static int parse_strings_from_string(int num_strings, char *data[],
 static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
 						    size_t count, loff_t *ppos)
 {
-	struct stm_chn_descriptor *chn_discriptor = filp->private_data;
+	struct stm_chn_descriptor *chn_descriptor = filp->private_data;
 	char *buf = NULL;
 	char *kbuf = NULL;
 	bool uspace = false;
@@ -132,26 +132,34 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
 	int header = 0;
 	int checksum = 0;
 
-	if (!chn_discriptor)
+	if (!chn_descriptor)
 		return -EFAULT;
 
-	if (!chn_discriptor->chn_enable)
+	if (!chn_descriptor->chn_enable)
 		return -EPERM;
 
-	if (chn_discriptor->write_protect)
-		if (mutex_lock_interruptible(&chn_discriptor->lock))
+	if (chn_descriptor->write_protect)
+		if (mutex_lock_interruptible(&chn_descriptor->lock))
 			return -ERESTARTSYS;
 
-	switch (chn_discriptor->msg_format) {
+	/* If channel's pid has changed export a notification message */
+	if (chn_descriptor->pid != current->pid && dev.stm_ops->write_mark) {
+		dev.stm_ops->write_mark(chn_descriptor->chn_id,
+				    (char *)&current->pid,
+				     sizeof current->pid, uspace,
+				     chn_descriptor->timestamp_enable);
+		chn_descriptor->pid = current->pid;
+	}
 
+	switch (chn_descriptor->msg_format) {
 	case USER:
-		timestamp = chn_discriptor->timestamp_enable;
+		timestamp = chn_descriptor->timestamp_enable;
 
 		/*determine how much space is needed */
-		if (chn_discriptor->checksum_enable)
+		if (chn_descriptor->checksum_enable)
 			checksum = 1;
 
-		if (chn_discriptor->ost_enable)
+		if (chn_descriptor->ost_enable)
 			header = ((count + checksum) < 256) ? 4 : 8;
 
 		if (count + header + checksum > STM_MAX_XFER_BYTES) {
@@ -161,7 +169,7 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
 
 		/* TODO:: If kmalloc sleeps (low memory case) then unprotected
 		 *	messages could get out of order. Consider putting
-		 *	in a small buffer (256 bytes) in the chn_discriptor.
+		 *	in a small buffer (256 bytes) in the chn_descriptor.
 		 *	In the unprotected case the user mode client is
 		 *	resposnible for using different channels per thread.
 		 */
@@ -177,29 +185,22 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
 			goto stm_file_write_exit;
 		}
 
-		if (chn_discriptor->ost_enable) {
+		if (chn_descriptor->ost_enable) {
 			if (header == 4)
 				*(uint32_t *)kbuf =  (uint32_t)(OST_VERSION
-					| (chn_discriptor->ost_entity << 16)
-					| (chn_discriptor->ost_protocol << 8)
+					| (chn_descriptor->ost_entity)
+					| (chn_descriptor->ost_protocol)
 					| (count + checksum));
 			else {
 				*(uint32_t *)kbuf =  (uint32_t)(OST_VERSION
-					| (chn_discriptor->ost_entity << 16)
-					| (chn_discriptor->ost_protocol << 8)
+					| (chn_descriptor->ost_entity)
+					| (chn_descriptor->ost_protocol)
 					| OST_SHORT_HEADER_LENGTH_LIMIT);
 				*(uint32_t *)(kbuf+1) =
 						  (uint32_t)(count + checksum);
 			}
 		}
 
-		/* TODO:: Implement checksum. Required for INVARIANT messages.
-		 *	May need to move the checksum to the first byte if
-		 *	continuous (> STM_MAX_XFER_BYTES) transfer implemented.
-		 */
-		/* Note:: TI host tools do not support checksum ( or INVARIANT
-		 * messages).
-		 */
 		if (checksum)
 			*(uint8_t *)(kbuf + header + count) =
 					    cal_checksum(kbuf, count + header);
@@ -226,7 +227,7 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
 
 	} /* End of switch */
 
-	ret = dev.stm_ops->write(chn_discriptor->chn, buf,
+	ret = dev.stm_ops->write(chn_descriptor->chn_id, buf,
 						   msg_cnt, uspace, timestamp);
 
 	/* Check for user mode case */
@@ -239,8 +240,8 @@ stm_file_write_exit:
 
 	kfree(kbuf);
 
-	if (chn_discriptor->write_protect)
-			mutex_unlock(&chn_discriptor->lock);
+	if (chn_descriptor->write_protect)
+			mutex_unlock(&chn_descriptor->lock);
 
 	return ret;
 }
@@ -273,7 +274,10 @@ enum config_id {
 	CFGID_FMT_USER,
 	CFGID_FMT_VENDOR,
 	CFGID_FMT_RAW,
-	CFGID_SET_HEADER,
+	CFGID_STRING,
+	CFGID_BINARY,
+	CFGID_OST_ENABLE,
+	CFGID_OST_DISABLE,
 	CFGID_TIMESTAMP_ENABLE,
 	CFGID_TIMESTAMP_DISABLE,
 	CFGID_CHECKSUM_ENABLE,
@@ -290,7 +294,10 @@ static char *config_cmds[] = {
 	[CFGID_FMT_USER] = "fmt_user",
 	[CFGID_FMT_VENDOR] = "fmt_vendor",
 	[CFGID_FMT_RAW] = "fmt_raw",
-	[CFGID_SET_HEADER] = "set_header",
+	[CFGID_STRING] = "string",
+	[CFGID_BINARY] = "binary",
+	[CFGID_OST_ENABLE] = "ost_enable",
+	[CFGID_OST_DISABLE] = "ost_disable",
 	[CFGID_TIMESTAMP_ENABLE] = "timestamp_enable",
 	[CFGID_TIMESTAMP_DISABLE] = "timestamp_disable",
 	[CFGID_CHECKSUM_ENABLE] = "checksum_enable",
@@ -302,104 +309,114 @@ static char *config_cmds[] = {
 static ssize_t config_file_write(struct file *file, const char __user *user_buf,
 				 size_t count, loff_t *ppos)
 {
-	struct stm_chn_descriptor *chn_discriptor = file->private_data;
-	char *kbuf = NULL;
+	struct stm_chn_descriptor *chn_descriptor = file->private_data;
+	char *kbuf = NULL, kbuffer[MAX_CONFIG_STRING_BYTES];
 	enum config_id cfg_id;
 	int cfg_len;
-	const int num_ulongs = 2;
-	const int max_ulong = 255;
-	long data[num_ulongs];
-	char delims[] = " ";
-	int err;
+	int err = 0;
+	bool vendor_pass = false;
 
 	if (count > MAX_CONFIG_STRING_BYTES) {
-		count = -EINVAL;
+		err = -EINVAL;
 		goto cfg_wrt_exit1;
 	}
 
-	kbuf = kmalloc(count, GFP_KERNEL);
-	if (!kbuf) {
-		count = -ENOMEM;
-		goto cfg_wrt_exit1;
-	}
+	/* Get userspace string and assure termination */
+	if (count >= sizeof(kbuffer))
+		return -EINVAL;
+
+	if (copy_from_user(kbuffer, user_buf, count))
+		return -EFAULT;
+
+	kbuffer[count] = 0;
 
-	copy_from_user(kbuf, user_buf, count);
+	/*
+	 * Allow "echo > request" or "echo -n '' > request"
+	 * to clean the filter quietly.
+	 */
+	kbuf = strstrip(kbuffer);
 
 	/* Check buf against list of supported commands (config_cmds) */
-	for (cfg_id = CFGID_CHN_ENABLE; cfg_id < CFGID_LAST; cfg_id++) {
+	for (cfg_id = 0; cfg_id < CFGID_LAST; cfg_id++) {
 		cfg_len = strlen(config_cmds[cfg_id]);
 		if (!strncmp(kbuf, config_cmds[cfg_id], cfg_len))
 			break;
 	}
 
-	if (mutex_lock_interruptible(&chn_discriptor->lock))
-		return -ERESTARTSYS;
+	if (mutex_lock_interruptible(&chn_descriptor->lock)) {
+		err = -ERESTARTSYS;
+		goto cfg_wrt_exit1;
+	}
 
 	switch (cfg_id) {
 	case CFGID_CHN_ENABLE:
-		chn_discriptor->chn_enable = true;
+		chn_descriptor->chn_enable = true;
 		break;
 	case CFGID_CHN_DISABLE:
-		chn_discriptor->chn_enable = false;
+		chn_descriptor->chn_enable = false;
 		break;
 	case CFGID_PROTECTED:
-		chn_discriptor->write_protect = true;
+		chn_descriptor->write_protect = true;
 		break;
 	case CFGID_UNPROTECTED:
-		chn_discriptor->write_protect = false;
+		chn_descriptor->write_protect = false;
 		break;
 	case CFGID_TIMESTAMP_ENABLE:
-		chn_discriptor->timestamp_enable = true;
+		chn_descriptor->timestamp_enable = true;
 		break;
 	case CFGID_TIMESTAMP_DISABLE:
-		chn_discriptor->timestamp_enable = false;
+		chn_descriptor->timestamp_enable = false;
 		break;
 	case CFGID_CHECKSUM_ENABLE:
-		chn_discriptor->checksum_enable = true;
+		chn_descriptor->checksum_enable = true;
 		break;
 	case CFGID_CHECKSUM_DISABLE:
-		chn_discriptor->checksum_enable = false;
+		chn_descriptor->checksum_enable = false;
 		break;
-	case CFGID_SET_HEADER:
-		chn_discriptor->ost_enable = false;
-		err = parse_ulongs_from_string(num_ulongs, max_ulong, data,
-								kbuf, delims);
-		if (err < 0) {
-			count = err;
-			goto cfg_wrt_exit2;
-		}
-		chn_discriptor->ost_entity = (char)data[0];
-		chn_discriptor->ost_protocol = (char)data[1];
-		chn_discriptor->ost_enable = true;
+	case CFGID_STRING:
+		chn_descriptor->ost_entity = OST_ENTITY_ID;
+		chn_descriptor->ost_protocol = OST_PROTOCOL_CHARSTREAM;
+		vendor_pass = true;
+		break;
+	case CFGID_BINARY:
+		chn_descriptor->ost_entity = OST_ENTITY_ID;
+		chn_descriptor->ost_protocol = OST_PROTOCOL_BINSTREAM;
+		vendor_pass = true;
+		break;
+	case CFGID_OST_ENABLE:
+		chn_descriptor->ost_enable = true;
+		break;
+	case CFGID_OST_DISABLE:
+		chn_descriptor->ost_enable = false;
 		break;
 	case CFGID_FMT_USER:
-		chn_discriptor->msg_format = USER;
-		count = dev.stm_ops->config_write(chn_discriptor->chn,
-								  kbuf, count);
+		chn_descriptor->msg_format = USER;
+		vendor_pass = true;
 		break;
 	case CFGID_FMT_VENDOR:
-		chn_discriptor->msg_format = VENDOR;
-		count = dev.stm_ops->config_write(chn_discriptor->chn,
-								  kbuf, count);
+		chn_descriptor->msg_format = VENDOR;
+		vendor_pass = true;
 		break;
 	case CFGID_FMT_RAW:
-		chn_discriptor->msg_format = RAW;
-		count = dev.stm_ops->config_write(chn_discriptor->chn,
-								  kbuf, count);
+		chn_descriptor->msg_format = RAW;
+		vendor_pass = true;
 		break;
 	default:
-		count = dev.stm_ops->config_write(chn_discriptor->chn,
-								  kbuf, count);
+		vendor_pass = true;
 	}
 
-cfg_wrt_exit2:
-	mutex_unlock(&chn_discriptor->lock);
+	if (vendor_pass)
+		err = dev.stm_ops->config_write(chn_descriptor->chn_id, kbuf);
+
+	mutex_unlock(&chn_descriptor->lock);
+
 cfg_wrt_exit1:
-	if ((int)count < 0)
-		printk(KERN_ALERT "stm_fw: invalid command format for %s, error %d\n",
-					  chn_discriptor->cfg_filename, count);
+	if (err) {
+		pr_err("stm_fw: invalid command ""%s"" for %s, error %d\n",
+				    kbuf, chn_descriptor->cfg_filename, err);
+		count = err;
+	}
 
-	kfree(kbuf);
 
 	return count;
 }
@@ -408,7 +425,7 @@ cfg_wrt_exit1:
 static ssize_t config_file_read(struct file *file, char __user *user_buf,
 				 size_t count, loff_t *ppos)
 {
-	struct stm_chn_descriptor *chn_discriptor = file->private_data;
+	struct stm_chn_descriptor *chn_descriptor = file->private_data;
 	const int max_buf = 256;
 	char buf[max_buf];
 	int buf_cnt = 0;
@@ -418,13 +435,14 @@ static ssize_t config_file_read(struct file *file, char __user *user_buf,
 	if (!dev.stm_ops->config_read)
 		return 0;
 
-	if (mutex_lock_interruptible(&chn_discriptor->lock))
+	if (mutex_lock_interruptible(&chn_descriptor->lock))
 		return -ERESTARTSYS;
 
 	/* config_read puts formatted comma seperated strings in buf */
-	buf_cnt = dev.stm_ops->config_read(chn_discriptor->chn, buf, max_buf);
+	buf_cnt = dev.stm_ops->config_read(chn_descriptor->chn_id,
+								buf, max_buf);
 
-	mutex_unlock(&chn_discriptor->lock);
+	mutex_unlock(&chn_descriptor->lock);
 
 	if (buf_cnt < 0)
 		return buf_cnt;
@@ -508,17 +526,7 @@ static ssize_t request_file_read(struct file *file, char __user *user_buf,
 }
 
 /* Request file write commands */
-
-enum request_id {
-	USER_CHANNEL_REQUEST,
-	PRINTK_CHANNEL_REQUEST,
-	TRACEPOINT_CHANEL_REQUEST,
-	LTTNG_CHANNEL_REQUEST,
-	REMOVE_CHANNEL_REQUEST,
-	LAST_REQUEST
-};
-
-static char *request_cmds[] = {
+static char *usecase_cmds[] = {
 	[USER_CHANNEL_REQUEST] = "user",
 	[PRINTK_CHANNEL_REQUEST] = "printk",
 	[TRACEPOINT_CHANEL_REQUEST] = "tracepoint_ftrace",
@@ -535,8 +543,8 @@ static ssize_t request_file_write(struct file *filp,
 {
 	int err = 0;
 	char *err_msg = "stm_fw: error creating <debugfs> file ";
-	char *buf = NULL;
-	enum request_id req_id;
+	char *kbuf = NULL, kbuffer[MAX_CONFIG_STRING_BYTES];
+	enum stm_usecase uc_id;
 	char filename[MAX_SIZE_FILENAME];
 	struct stm_chn_descriptor *chn_descriptor = NULL;
 	char *username = NULL;
@@ -544,26 +552,35 @@ static ssize_t request_file_write(struct file *filp,
 	struct list_head *ptr;
 	bool name_hit = false;
 
-	buf = kmalloc(count, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
+	/* Get userspace string and assure termination */
+	if (count >= sizeof(kbuffer))
+		return -EINVAL;
+
+	copy_from_user(kbuffer, user_buf, count);
 
-	copy_from_user(buf, user_buf, count);
+	kbuffer[count] = 0;
+
+	/*
+	 * Allow "echo > request" or "echo -n '' > request"
+	 * to clean the filter quietly.
+	 */
+
+	kbuf = strstrip(kbuffer);
 
 	/* Check buf against the list of supported commands */
-	for (req_id = USER_CHANNEL_REQUEST; req_id < LAST_REQUEST; req_id++)
-		if (!strncmp(buf, request_cmds[req_id],
-					strlen(request_cmds[req_id])))
+	for (uc_id = 0; uc_id < LAST_REQUEST; uc_id++)
+		if (!strncmp(kbuf, usecase_cmds[uc_id],
+					strlen(usecase_cmds[uc_id])))
 			break;
 
-	if (req_id < LAST_REQUEST) {
+	if (uc_id < LAST_REQUEST) {
 		/*
 		 * Parse out the filename. For all cases currently supported.
 		 * If case not support next switch takes default to call
 		 * vendor drvier's write config function.
 		 */
 		char *delims = " ";
-		err = parse_strings_from_string(1, &username, buf, delims);
+		err = parse_strings_from_string(1, &username, kbuf, delims);
 		if (err < 0)
 			goto err_exit;
 	}
@@ -571,7 +588,7 @@ static ssize_t request_file_write(struct file *filp,
 	if (mutex_lock_interruptible(&dev.lock))
 		return -ERESTARTSYS;
 
-	switch (req_id) {
+	switch (uc_id) {
 	case USER_CHANNEL_REQUEST:
 	case PRINTK_CHANNEL_REQUEST:
 	case TRACEPOINT_CHANEL_REQUEST:
@@ -604,14 +621,6 @@ static ssize_t request_file_write(struct file *filp,
 			goto err_exit;
 		}
 
-		/* Allocate a channel */
-		chn_descriptor->chn = dev.stm_ops->allocate_channel(
-							request_cmds[req_id]);
-		if (chn_descriptor->chn < 0) {
-			err = chn_descriptor->chn;
-			goto alloc_err_exit;
-		}
-
 		/* Initialize chn descriptor */
 		chn_descriptor->write_dentry = NULL;
 		chn_descriptor->config_dentry = NULL;
@@ -620,12 +629,24 @@ static ssize_t request_file_write(struct file *filp,
 
 		mutex_init(&chn_descriptor->lock);
 		chn_descriptor->msg_format = VENDOR;
-		chn_descriptor->msg_type = GUARANTEED;
+		chn_descriptor->msg_timing = GUARANTEED;
+		chn_descriptor->ost_protocol = OST_PROTOCOL_CHARSTREAM;
+		chn_descriptor->ost_entity = OST_ENTITY_ID;
 		chn_descriptor->timestamp_enable = true;
 		chn_descriptor->checksum_enable = false;
+		/* set to invlaid id so first write will export pid message */
+		chn_descriptor->pid = 0;
+
+		/* Allocate a channel */
+		err = dev.stm_ops->allocate_channel(uc_id,
+						    &chn_descriptor->chn_id);
+		if (err < 0) {
+			chn_descriptor->chn_id = NULL;
+			goto alloc_err_exit;
+		}
 
 		/* If user command create debugfs message write file */
-		if (req_id == USER_CHANNEL_REQUEST) {
+		if (uc_id == USER_CHANNEL_REQUEST) {
 
 			len = strlen(username);
 			if (len > MAX_SIZE_FILENAME || !len) {
@@ -708,7 +729,7 @@ static ssize_t request_file_write(struct file *filp,
 		break;
 
 	default:
-		err = dev.stm_ops->config_write(-1, buf, count);
+		err = dev.stm_ops->config_write((void *)-1, kbuf);
 		if (err < 0) {
 			err = -EINVAL;
 			goto err_exit;
@@ -716,21 +737,25 @@ static ssize_t request_file_write(struct file *filp,
 
 	} /* End of the switch */
 
-	kfree(buf);
 	*f_pos += count;
 	mutex_unlock(&dev.lock);
 	return count;
 
 alloc_err_exit:
 	rm_chn_descriptor(chn_descriptor);
+	kfree(chn_descriptor);
 
 err_exit:
-	kfree(buf);
-
 	mutex_unlock(&dev.lock);
-
 	return err;
+}
+
+static int request_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!dev.stm_ops->mmap)
+		return -EACCES;
 
+	return dev.stm_ops->mmap(vma);
 
 }
 
@@ -745,7 +770,8 @@ static int request_file_open(struct inode *inode, struct file *file)
 
 static const struct file_operations request_fop = {
 	.write = request_file_write,
-	.read =	 request_file_read,
+	.read =	request_file_read,
+	.mmap = request_file_mmap,
 	.open =	 request_file_open,
 };
 
@@ -797,7 +823,7 @@ int stm_register(struct stm_operations *module_ops)
 		goto stm_register_err;
 	}
 
-	pr_err("stm_fw: vendor driver %s registered\n", module_ops->name);
+	pr_info("stm_fw: vendor driver %s registered\n", module_ops->name);
 
 	dev.stm_ops = module_ops;
 	INIT_LIST_HEAD(&dev.chn_list_head);
@@ -808,42 +834,41 @@ stm_register_err:
 }
 EXPORT_SYMBOL(stm_register);
 
-int stm_unregister(char *name)
+int stm_unregister()
 {
-	int ret = 0;
 	struct stm_chn_descriptor *chn_descriptor;
 	struct list_head *ptr;
 
 	if (mutex_lock_interruptible(&dev.lock))
 		return -ERESTARTSYS;
 
-	if (strcmp(dev.stm_ops->name, name)) {
-		ret = -EINVAL;
-		goto stm_unregister_err;
-	}
-
 	list_for_each(ptr, &dev.chn_list_head) {
 		chn_descriptor = list_entry(ptr, struct stm_chn_descriptor,
 								chn_list_link);
 
+		if (mutex_lock_interruptible(&chn_descriptor->lock)) {
+			mutex_unlock(&dev.lock);
+			return -ERESTARTSYS;
+		}
+
 		if (chn_descriptor->write_dentry)
 			debugfs_remove(chn_descriptor->write_dentry);
 
 		if (chn_descriptor->config_dentry)
 			debugfs_remove(chn_descriptor->config_dentry);
 
-		if (chn_descriptor->chn >= 0)
-			dev.stm_ops->free_channel(chn_descriptor->chn);
+		mutex_unlock(&chn_descriptor->lock);
 
 		kfree(chn_descriptor);
+
 	}
 
 	debugfs_remove_recursive(dev.parent);
-	dev.stm_ops = NULL;
 
 	pr_info("stm_fw: vendor driver %s removed\n", dev.stm_ops->name);
 
-stm_unregister_err:
+	dev.stm_ops = NULL;
+
 	mutex_unlock(&dev.lock);
 
 	return 0;
@@ -863,10 +888,6 @@ static int stm_fw_init(void)
 
 static void stm_fw_exit(void)
 {
-
-	if (dev.stm_ops)
-		stm_unregister(dev.stm_ops->name);  /* rm the request file*/
-
 	pr_info("stm_fw: driver exit\n");
 }
 
@@ -877,12 +898,14 @@ MODULE_LICENSE("Dual BSD/GPL");
 /*****************************************************************************/
 /* Support functions							 */
 /*****************************************************************************/
-
-/* TODO:: Implement cal_checksum(). */
-
-static uint8_t cal_checksum(char *buf, int cnt)
+static int8_t cal_checksum(unsigned char *buf, int cnt)
 {
-	return 0;
+	int i;
+	uint8_t checksum = 0;
+	for (i = 0; i < cnt; i++)
+		checksum += buf[i];
+
+	return -checksum;
 }
 
 static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor)
@@ -896,10 +919,9 @@ static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor)
 	if (chn_descriptor->config_dentry)
 		debugfs_remove(chn_descriptor->config_dentry);
 
-	if (chn_descriptor->chn >= 0)
-		dev.stm_ops->free_channel(chn_descriptor->chn);
+	if (chn_descriptor->chn_id)
+		dev.stm_ops->free_channel(chn_descriptor->chn_id);
 
-	kfree(chn_descriptor);
 }
 
 
@@ -925,7 +947,7 @@ static int parse_to_user(char *buf, loff_t buf_pos,
 	item = strsep(next, delims);
 	do {
 		item_len = strlen(item);
-		if ((item_len <= count) && (buf_pos == *ppos)) {
+		if (item_len <= count && buf_pos == *ppos) {
 			loff_t copy_pos = 0;
 			/* copy item to user buf */
 			copy_len = simple_read_from_buffer(user_buf, count,
@@ -955,35 +977,6 @@ static int parse_to_user(char *buf, loff_t buf_pos,
 /* Note, this function assumes first string is a command (which has already
  * been evaluated) is to be thrown away.
  */
-static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
-						    char *kbuf, char *delims)
-{
-	/* Parse the set header command */
-	int i;
-	int ret;
-	char **item = &kbuf;
-	/* Get command - throw it away */
-	char *param = strsep(item, delims);
-
-	/* Get next two parameter values */
-	for (i = 0; i < num_longs; i++) {
-		param = strsep(item, delims);
-		if (!param)
-			return -EINVAL;
-
-		ret = kstrtol(param, 10, &data[i]);
-		if (ret)
-			return ret;
-
-		if (data[i] < 0 || data[i] > max_ulong)
-			return -EINVAL;
-	}
-	return 0;
-}
-
-/* Note, this function assumes first string is a command (which has already
- * been evaluated) is to be thrown away.
- */
 static int parse_strings_from_string(int num_strings, char *data[],
 						    char *kbuf, char *delims)
 {
diff --git a/drivers/stm/stm_fw.h b/drivers/stm/stm_fw.h
index e6bf041..bcaa307 100644
--- a/drivers/stm/stm_fw.h
+++ b/drivers/stm/stm_fw.h
@@ -39,6 +39,15 @@
 #ifndef _STM_FW_H
 #define _STM_FW_H
 
+enum stm_usecase {
+	USER_CHANNEL_REQUEST,
+	PRINTK_CHANNEL_REQUEST,
+	TRACEPOINT_CHANEL_REQUEST,
+	LTTNG_CHANNEL_REQUEST,
+	REMOVE_CHANNEL_REQUEST,
+	LAST_REQUEST
+};
+
 struct stm_global_info {
 	int     total_chn_cnt;
 	int     reserved_chn_cnt;
@@ -51,17 +60,18 @@ struct stm_global_info {
 struct stm_operations {
 	char    *name;
 	int     (*get_global_info)(struct stm_global_info *info);
-	int     (*write) (int chn, char *pbuf, int cnt, bool uspace,
+	int     (*write) (void *chn_id, char *pbuf, int cnt, bool uspace,
 			  bool timestamp);
-	int     (*write_mark)(int chn, char *pbuf, int cnt, bool uspace,
+	int     (*write_mark)(void *chn_id, char *pbuf, int cnt, bool uspace,
 			      bool timestamp);
-	int     (*allocate_channel) (char *usecase);
-	int     (*free_channel) (int chn);
-	int     (*config_write)(int chn, char *config_string, int count);
-	int     (*config_read)(int chn, char *config_string, int count);
+	int     (*allocate_channel) (enum stm_usecase uc_id, void **chn_id);
+	int     (*free_channel) (void *chn_id);
+	int     (*config_write)(void *chn_id, char *config_string);
+	int     (*config_read)(void *chn_id, char *config_string, int count);
 	int     (*mmap)(struct vm_area_struct *vma);
 };
 
 int stm_register(struct stm_operations *stm_ops);
+int stm_unregister(void);
 
 #endif
diff --git a/drivers/stm/stm_msg.h b/drivers/stm/stm_msg.h
index f40e0a9..9a6326a 100644
--- a/drivers/stm/stm_msg.h
+++ b/drivers/stm/stm_msg.h
@@ -44,17 +44,20 @@
 #ifndef __STM_MSG_H_
 #define __STM_MSG_H_
 
-enum msg_formats {USER, VENDOR, RAW};
-enum msg_types {GUARANTEED, INVARIANT};
+enum msg_format_t {USER, VENDOR, RAW};
+enum msg_data_t {STRING, BIN8, BIN16, BIN32};
+enum msg_timing_t {GUARANTEED, INVARIANT};
 
 
 #define OST_VERSION	(1 << 24)     /* note:must be between 1 and 15 */
 #define OST_ENTITY_ID	(1 << 16)
 
-#define OST_PROTOCOL_BYTESTREAM	(0x81 << 8)	/* STMXport_putMsg */
+#define OST_PROTOCOL_CHARSTREAM	(0x81 << 8)	/* String data                */
+#define OST_PROTOCOL_BINSTREAM	(0x82 << 8)	/* Binary data                */
 #define OST_SHORT_HEADER_LENGTH_LIMIT	(255)
-#define STM_1_MAX_CHANNEL (240)
-/* chnls 240-255 reserved for TI debug tools */
+#define STM_1_MAX_CHANNEL (240)			/* chnls 240-255 reserved for
+						 * TI debug tools.
+						 */
 
 #define STM_MAX_XFER_BYTES  4096    /*
 				     * Maximum nuimber of bytes to transfer per
diff --git a/drivers/stm/stm_omap_ti1.0.c b/drivers/stm/stm_omap_ti1.0.c
index 4dfe853..c401749 100644
--- a/drivers/stm/stm_omap_ti1.0.c
+++ b/drivers/stm/stm_omap_ti1.0.c
@@ -45,6 +45,8 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/version.h>
 
 #include "stm_fw.h"
 #include "stm_msg.h"
@@ -61,7 +63,11 @@ static void build_ost_header(uint32_t protocol_id, uint32_t size,
 static int32_t stm_put_msg(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
 			   uint32_t msg_size, int32_t chn, bool timestamp);
 
-static struct chn_alloc *find_chn_object(int chn);
+static int32_t stm_put_bin(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
+			      enum msg_data_t element_type, uint32_t num_bytes,
+					      int32_t stm_chn, bool timestamp);
+
+static struct chn_alloc *construct_chn_obj(int chn, int chn_num);
 
 static bool stm_app_ownership(void);
 
@@ -81,11 +87,11 @@ static bool stm_test_clock(void);
 				      * any one time */
 #define HW_MASTER_MASK       0x80    /* All HW masters have bit 7 set */
 
-#define STM_CONTROL_BASE
-
 #define ATTRIBUTE_BUF_SIZE    256
 static char attribute_buf[ATTRIBUTE_BUF_SIZE];
 
+#define CONTEXT_PID_MSG_MAX     32
+
 static const uint32_t stm_base_address = L4_EMU_44XX_BASE;
 static const uint32_t stm_resolution = 0x1000;
 static uint32_t stm_iobase;
@@ -155,8 +161,10 @@ static struct stm_device dev;
 
 struct chn_alloc {
 	u8 chn;
+	int chn_num;		/* Number of consecutive channels allocated */
 	int xmit_byte_count;
-	enum msg_formats chn_msg_format;
+	enum msg_format_t msg_format;
+	enum msg_data_t msg_data_type;
 	struct mutex chn_lock;
 	struct list_head chn_list_link;
 };
@@ -210,7 +218,7 @@ int get_global_info(struct stm_global_info *info)
 }
 
 /* Write buf to STM port */
-int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
+int stm_write(void *chn_id, char *buf, int cnt, bool uspace, bool timestamp)
 {
 
 	/*
@@ -221,17 +229,13 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
 	 */
 	int ret = 0;
 	const char *local_buf = NULL;
-	struct chn_alloc *chn_obj = find_chn_object(chn);
+	struct chn_alloc *chn_obj = chn_id;
 	int hdr_size = 0;
 	uint32_t ost_header[2] = { 0 };
+	uint32_t ost_protocol;
 
-	if (chn_obj < 0)
-		return (int)chn_obj;
-
-	if (!buf || cnt < 1 || !chn_obj) {
-		ret = -EINVAL;
-		goto stm_write_exit;
-	}
+	if (!buf || cnt < 1 || !chn_obj)
+		return -EINVAL;
 
 	/*
 	 * Provide protection for chn_obj accesses and keeps all
@@ -240,7 +244,7 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
 	if (mutex_lock_interruptible(&chn_obj->chn_lock))
 		return -ERESTARTSYS;
 
-	switch (chn_obj->chn_msg_format) {
+	switch (chn_obj->msg_format) {
 
 	case VENDOR:
 		if (uspace) {
@@ -258,16 +262,32 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
 				ret = -EFAULT;
 				goto stm_write_exit;
 			}
+		} else {
+			local_buf = buf;
 		}
 
 		/* Send message over STM channel */
-		build_ost_header((uint32_t)OST_PROTOCOL_BYTESTREAM, cnt,
-					    (uint32_t *)ost_header, &hdr_size);
-		ret = stm_put_msg((void *)ost_header, hdr_size,
-				       (void *)local_buf, cnt, chn, timestamp);
+		ost_protocol = (STRING == chn_obj->msg_data_type)
+					  ? OST_PROTOCOL_CHARSTREAM
+					  : OST_PROTOCOL_BINSTREAM;
+
+		build_ost_header(ost_protocol, cnt,
+					(uint32_t *)ost_header, &hdr_size);
+
+		if (STRING == chn_obj->msg_data_type)
+			ret = stm_put_msg((void *)ost_header, hdr_size,
+						(void *)local_buf, cnt,
+						chn_obj->chn, timestamp);
+		else
+			ret = stm_put_bin((void *)ost_header, hdr_size,
+				     (void *)local_buf, chn_obj->msg_data_type,
+				     cnt, chn_obj->chn, timestamp);
 		if (!ret)
 			ret = cnt;
 
+		if (!uspace)
+			local_buf = NULL;
+
 		break;
 
 	case USER:
@@ -275,7 +295,14 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
 		 * No need to worry about exceeding STM_MAX_XFER_BYTES because
 		 * stm_fw driver takes care of this check.
 		 */
-		ret = stm_put_msg(NULL, 0, (void *)buf, cnt, chn, timestamp);
+		if (STRING == chn_obj->msg_data_type) {
+			ret = stm_put_msg(NULL, 0, (void *)buf, cnt,
+						chn_obj->chn, timestamp);
+		} else {
+			ret = stm_put_bin(NULL, 0, (void *)buf,
+						chn_obj->msg_data_type,
+						cnt, chn_obj->chn, timestamp);
+		}
 		if (!ret)
 			ret = cnt;
 
@@ -298,45 +325,53 @@ stm_write_exit:
 	return ret;
 }
 
-enum usecase_id {
-	USECASE_USER,
-	USECASE_PRINTK,
-	USECASE_LAST
-};
+int stm_write_mark(void *chn_id, char *pbuf, int cnt, bool uspace,
+								bool timestamp)
+{
+	int ret = 0;
+	const int pid_msg_max = 64;
+	char pid_msg[pid_msg_max];
+	uint msg_cnt;
+	struct chn_alloc *chn_obj = chn_id;
+	enum msg_format_t orig_msg_format = chn_obj->msg_format;
+	enum msg_data_t orig_msg_data_type = chn_obj->msg_data_type;
 
-static char *usecase_cmds[] = {
-	[USECASE_USER] = "user",
-	[USECASE_PRINTK] = "printk"
-};
+	msg_cnt = snprintf(pid_msg, pid_msg_max, "PID %d using STM Channel %d",
+						*(pid_t *)pbuf, chn_obj->chn);
+
+	chn_obj->msg_format = VENDOR;
+	chn_obj->msg_data_type = STRING;
+
+	ret = stm_write(chn_id, pid_msg, msg_cnt, uspace, timestamp);
 
-int stm_allocate_channel(char *usecase)
+	chn_obj->msg_format = orig_msg_format;
+	chn_obj->msg_data_type = orig_msg_data_type;
+
+	return ret;
+}
+
+int stm_allocate_channel(enum stm_usecase uc_id, void **chn_id)
 {
 	int chn;
 	int ret = 0;
 	int chn_offset;
 	int chn_num;
 	int chn_last;
-	enum usecase_id uc_id;
 	struct chn_alloc *chn_obj;
 
+	*chn_id = NULL;
+
 	if (mutex_lock_interruptible(&dev.lock))
 		return -ERESTARTSYS;
 
-	/* Search for the supported usecase id */
-	for (uc_id = USECASE_USER; uc_id < USECASE_LAST; uc_id++)
-		if (!strncmp(usecase, usecase_cmds[uc_id],
-					strlen(usecase_cmds[uc_id])))
-			break;
-
 	switch (uc_id) {
-
-	case USECASE_USER:
+	case USER_CHANNEL_REQUEST:
 		chn_num = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
 		chn_offset = STM_START_ALLOC;
 		chn_last = chn_num;
 		break;
 
-	case USECASE_PRINTK:
+	case PRINTK_CHANNEL_REQUEST:
 		chn_num = STM_CHANNEL_RESERVED;
 		chn_offset = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
 		chn_last = STM_CHANNEL_TOTAL;
@@ -347,6 +382,8 @@ int stm_allocate_channel(char *usecase)
 		goto stm_allocate_channel_exit;
 	}
 
+/*TODO: Can simplify since using a mutex to protect */
+
 	/* Look for a free channel from channel map - note thread safe test */
 	do {
 		chn = find_next_zero_bit(dev.chn_map, chn_num, chn_offset);
@@ -357,20 +394,13 @@ int stm_allocate_channel(char *usecase)
 		goto stm_allocate_channel_exit;
 	}
 
-	chn_obj = kmalloc(sizeof(struct chn_alloc), GFP_KERNEL);
-	if (!chn_obj) {
-		ret = -ENOMEM;
+	chn_obj = construct_chn_obj(chn, 1);
+	if (IS_ERR(chn_obj)) {
+		ret = PTR_ERR(chn_obj);
 		goto stm_allocate_channel_exit;
 	}
 
-	mutex_init(&chn_obj->chn_lock);
-	chn_obj->chn = chn;
-	chn_obj->chn_msg_format = VENDOR;
-	chn_obj->xmit_byte_count = 0;
-
-	list_add(&chn_obj->chn_list_link, &dev.chn_list_head);
-	dev.user_allocated_chn_cnt++;
-	ret = chn;
+	*chn_id = chn_obj;
 
 stm_allocate_channel_exit:
 
@@ -379,51 +409,165 @@ stm_allocate_channel_exit:
 
 }
 
-int stm_free_channel(int chn)
+int stm_free_channel(void *chn_id)
 {
-	struct list_head *ptr;
-	struct chn_alloc *chn_obj = NULL;
+	int i;
+	struct chn_alloc *chn_obj = chn_id;
 
 	if (mutex_lock_interruptible(&dev.lock))
 		return -ERESTARTSYS;
 
-	list_for_each(ptr, &dev.chn_list_head) {
-		chn_obj = list_entry(ptr, struct chn_alloc, chn_list_link);
-		if (!chn_obj || chn != chn_obj->chn)
-			continue;
+	/* Make sure nobody else is using the channel. */
+	if (mutex_lock_interruptible(&chn_obj->chn_lock)) {
+		mutex_unlock(&dev.lock);
+		return -ERESTARTSYS;
+	}
 
-		/* Make sure nobody else is using the channel. */
-		if (mutex_lock_interruptible(&chn_obj->chn_lock)) {
-			mutex_unlock(&dev.lock);
-			return -ERESTARTSYS;
-		}
-		/* Remove the channel from the link list. */
-		list_del(ptr);
-		/* Safe to unlock. */
-		mutex_unlock(&chn_obj->chn_lock);
+	/* Remove the channel from the link list. */
+	list_del(&chn_obj->chn_list_link);
+
+	/* Safe to unlock. */
+	mutex_unlock(&chn_obj->chn_lock);
 
-		clear_bit(chn, dev.chn_map);
+	/* Free channels */
+	for (i = chn_obj->chn; i < chn_obj->chn + chn_obj->chn_num; i++) {
+		clear_bit(i, dev.chn_map);
 		dev.user_allocated_chn_cnt--;
-		kfree(chn_obj);
-		break;
 	}
 
+	kfree(chn_obj);
+
 	mutex_unlock(&dev.lock);
 
 	return 0;
 }
 
+/* close function used to free the allocated channels */
+void vm_mmap_close(struct vm_area_struct *vma)
+{
+	struct chn_alloc *chn_obj = vma->vm_private_data;
+
+	stm_free_channel(chn_obj);
+
+}
+
+/* nopage currently simply sends a NOPAGE signal */
+int vm_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+
+	return VM_FAULT_SIGBUS;
+}
+/* Note: Can add vma_mmap_open to support allocating new
+ * STM channels for a forked process. Our assuption is users
+ * will mmap channles required after fork.
+ * Can add a vma_mmap_nopage to deal with page faults and mremap
+ * to allocat or extend an existing allocation of physical
+ * STM port addresses, automatically mapping them for the
+ * user space application. Our assumption is users will simply
+ * use mmap.
+ */
+static struct vm_operations_struct vma_mmap_ops = {
+	.close = vm_mmap_close,
+	.fault = vm_mmap_fault
+};
+
+/* Map each 4K (stm channel resolution) of user virtual address space
+ * to physical STM channel ports.
+ */
+int stm_mmap_channels(struct vm_area_struct *vma)
+{
+	int ret = 0;
+	int i;
+	unsigned long vma_size = vma->vm_end - vma->vm_start;
+	int num_chn_requested = vma_size/stm_resolution;
+	int orig_num_chan_requested = num_chn_requested;
+
+	int chn_num = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
+
+	int first_chn = STM_START_ALLOC;
+	int next_chn = STM_START_ALLOC;
+	int this_chn;
+
+	uint32_t phy_stm_address;
+	struct chn_alloc *chn_obj;
+
+	if (!num_chn_requested)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&dev.lock))
+		return -ERESTARTSYS;
+
+	/* Search for a block of free channels */
+	while (num_chn_requested-- > 0) {
+
+		/* Test the next channel is avaiable */
+		this_chn = find_next_zero_bit(dev.chn_map, chn_num, next_chn);
+
+		/* Check we have run out of channels */
+		if (this_chn == chn_num) {
+			ret = -EACCES;
+			goto stm_mmap_channels_err;
+		}
+
+		/* Test for the next consecutive channel not free */
+		if (this_chn != next_chn) {
+			first_chn = this_chn;
+			num_chn_requested = orig_num_chan_requested - 1;
+		}
+		next_chn = this_chn + 1;
+
+	}
+	/* Set the bits for each channel found where next_chn is now
+	 * the next channel outside the range.
+	 */
+	for (i = first_chn; i < next_chn; i++)
+		set_bit(i, dev.chn_map);
+
+	chn_obj = construct_chn_obj(first_chn, orig_num_chan_requested);
+	if (IS_ERR(chn_obj)) {
+		ret = PTR_ERR(chn_obj);
+		goto stm_mmap_channels_err;
+	}
+
+	mutex_unlock(&dev.lock);
+
+	/* Can now map range of first_chn to next_chn-1 */
+	phy_stm_address = stm_base_address + (first_chn * stm_resolution);
+	if (remap_pfn_range(vma, vma->vm_start, phy_stm_address>>PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		ret = -EAGAIN;
+
+	vma->vm_private_data = (void *)chn_obj;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	vma->vm_page_prot |= PAGE_SHARED;
+	vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP;
+	vma->vm_ops = &vma_mmap_ops;
+
+	return ret;
+
+
+stm_mmap_channels_err:
+
+	mutex_unlock(&dev.lock);
+
+	return ret;
+}
+
 enum config_id {
 	CFGID_FMT_USER,
 	CFGID_FMT_VENDOR,
 	CFGID_FMT_RAW,
+	CFGID_STRING,
+	CFGID_BIN8,
+	CFGID_BIN16,
+	CFGID_BIN32,
+	CFGID_GUARANTEED_TIMING,
 	CFGID_ROUTE_TO_PTI,
 	CFGID_ROUTE_TO_ETB,
 	CFGID_SET_MASTER,
 	CFGID_CLR_MASTER,
 	CFGID_STM_ENABLE,
 	CFGID_STM_DISABLE,
-	CFGID_GUARANTEED_TIMING,
 	CFGID_LAST
 };
 
@@ -431,17 +575,22 @@ static char *config_cmds[] = {
 	[CFGID_FMT_USER] = "fmt_user",
 	[CFGID_FMT_VENDOR] = "fmt_vendor",
 	[CFGID_FMT_RAW] = "fmt_raw",
+	[CFGID_STRING] = "string",
+	[CFGID_BIN8] = "binary8",
+	[CFGID_BIN16] = "binary16",
+	[CFGID_BIN32] = "binary32",
+	[CFGID_GUARANTEED_TIMING] = "guaranteed",
 	[CFGID_ROUTE_TO_PTI] = "route_stm_to_pti",
 	[CFGID_ROUTE_TO_ETB] = "route_stm_to_etb",
 	[CFGID_SET_MASTER] = "set_master",
 	[CFGID_CLR_MASTER] = "clr_master",
 	[CFGID_STM_ENABLE] = "stm_enable",
 	[CFGID_STM_DISABLE] = "stm_disable",
-	[CFGID_GUARANTEED_TIMING] = "guaranteed"
+
 };
 
 
-int stm_config_write(int chn, char *config_buf, int count)
+int stm_config_write(void *chn_id, char *config_buf)
 {
 	int ret = 0;
 	struct chn_alloc *chn_obj;
@@ -457,19 +606,17 @@ int stm_config_write(int chn, char *config_buf, int count)
 	char delims[] = " ";
 	uint32_t control;
 
-	chn_obj = (chn > -1) ? find_chn_object(chn) : NULL;
-	if (chn_obj < 0)
-		return (int)chn_obj;
-
-	if (!config_buf || count < 1 || (!chn_obj && chn > -1))
+	if (!config_buf || !chn_id)
 		return  -EINVAL;
 
+	chn_obj = ((int)chn_id != -1) ? chn_id : NULL;
+
 	if (chn_obj)
 		if (mutex_lock_interruptible(&chn_obj->chn_lock))
 			return -ERESTARTSYS;
 
 	/* check buf against list of supported features */
-	for (cfg_id = CFGID_FMT_USER; cfg_id < CFGID_LAST; cfg_id++)
+	for (cfg_id = 0; cfg_id < CFGID_LAST; cfg_id++)
 		if (!strncmp(config_buf, config_cmds[cfg_id],
 						strlen(config_cmds[cfg_id])))
 			break;
@@ -483,18 +630,29 @@ int stm_config_write(int chn, char *config_buf, int count)
 	switch (cfg_id) {
 
 	case CFGID_FMT_USER:
-		chn_obj->chn_msg_format = USER;
+		chn_obj->msg_format = USER;
 		break;
 
 	case CFGID_FMT_VENDOR:
-		chn_obj->chn_msg_format = VENDOR;
+		chn_obj->msg_format = VENDOR;
 		break;
 
 	case CFGID_FMT_RAW:
-		chn_obj->chn_msg_format = RAW;
+		chn_obj->msg_format = RAW;
 		ret = -EINVAL;
 		goto stm_config_write_exit;
-
+	case CFGID_STRING:
+		chn_obj->msg_data_type = STRING;
+		break;
+	case CFGID_BIN8:
+		chn_obj->msg_data_type = BIN8;
+		break;
+	case CFGID_BIN16:
+		chn_obj->msg_data_type = BIN16;
+		break;
+	case CFGID_BIN32:
+		chn_obj->msg_data_type = BIN32;
+		break;
 	case CFGID_ROUTE_TO_ETB:
 		/* Note: call stm_app_ownership first*/
 		/* Note: need to set rate at which masters are generated
@@ -580,8 +738,10 @@ int stm_config_write(int chn, char *config_buf, int count)
 		control = ioread32((void *)(stm_cntl_iobase
 						       + STM_SWMCTRL0_OFFSET));
 
-		if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_ENABLED)
-			return -EFAULT;
+		if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_ENABLED) {
+			ret = -EFAULT;
+			goto stm_config_write_exit;
+		}
 
 		break;
 
@@ -602,8 +762,10 @@ int stm_config_write(int chn, char *config_buf, int count)
 		control = ioread32((void *)(stm_cntl_iobase
 						       + STM_SWMCTRL0_OFFSET));
 
-		if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE)
-			return -EFAULT;
+		if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE) {
+			ret = -EFAULT;
+			goto stm_config_write_exit;
+		}
 
 		break;
 
@@ -612,11 +774,9 @@ int stm_config_write(int chn, char *config_buf, int count)
 		break;
 	default:
 		/* If the config request not supported */
-		 count = -EINVAL;
+		ret = -EINVAL;
 	}
 
-	ret = count;
-
 stm_config_write_exit:
 
 	if (chn_obj)
@@ -627,16 +787,13 @@ stm_config_write_exit:
 }
 
 /* Provide comma seperated list of configuration and channel state info. */
-int stm_config_read(int chn, char *config_string, int count)
+int stm_config_read(void *chn_id, char *config_string, int count)
 {
 
-	struct chn_alloc *chn_obj = find_chn_object(chn);
+	struct chn_alloc *chn_obj = chn_id;
 	int buf_cnt = 0;
 	char *chn_format = NULL;
 
-	if (IS_ERR(chn_obj))
-		return PTR_ERR(chn_obj);
-
 	if (!config_string || count < 1 || !chn_obj)
 		return -EINVAL;
 
@@ -646,7 +803,7 @@ int stm_config_read(int chn, char *config_string, int count)
 	buf_cnt = snprintf(config_string, count, "STM channel %d\n,",
 							chn_obj->chn);
 
-	switch (chn_obj->chn_msg_format) {
+	switch (chn_obj->msg_format) {
 	case VENDOR:
 		chn_format = config_cmds[CFGID_FMT_VENDOR];
 		break;
@@ -677,10 +834,12 @@ static struct stm_operations stm_ti_ops = {
 	.name = "stm_ti1.0",
 	.get_global_info = get_global_info,
 	.write = stm_write,
+	.write_mark = stm_write_mark,
 	.allocate_channel = stm_allocate_channel,
 	.free_channel = stm_free_channel,
 	.config_write = stm_config_write,
-	.config_read = stm_config_read
+	.config_read = stm_config_read,
+	.mmap = stm_mmap_channels
 };
 
 
@@ -694,19 +853,18 @@ void stm_ti_clean(void)
 		kfree(chn_obj);
 	}
 
-	release_mem_region(stm_base_address, STM_ADDRESS_SPACE);
-	release_mem_region(stm_control_base, STM_ADDRESS_SPACE);
-
-
-	if (!stm_iobase) {
+	if (stm_iobase) {
 		iounmap((void *)stm_iobase);
 		stm_iobase = 0;
 	}
 
-	if (!stm_cntl_iobase) {
+	if (stm_cntl_iobase) {
 		iounmap((void *)stm_cntl_iobase);
 		stm_cntl_iobase = 0;
 	}
+
+	release_mem_region(stm_base_address, STM_ADDRESS_SPACE);
+	release_mem_region(stm_control_base, STM_ADDRESS_SPACE);
 }
 
 
@@ -714,10 +872,9 @@ int __init stm_ti_init(void)
 {
 
 	int ret = 0;
-	char *mod_name = "STM 1.0 Module";
 
 	if (!request_mem_region(stm_base_address, STM_ADDRESS_SPACE,
-								mod_name)) {
+							 stm_ti_ops.name)) {
 		ret = -ENODEV;
 		goto init_err;
 	}
@@ -730,7 +887,7 @@ int __init stm_ti_init(void)
 	}
 
 	if (!request_mem_region(stm_control_base, STM_ADDRESS_SPACE,
-								mod_name)) {
+							 stm_ti_ops.name)) {
 		ret = -ENODEV;
 		goto init_err;
 	}
@@ -762,8 +919,9 @@ init_err:
 
 void __exit stm_ti_exit(void)
 {
-	pr_info("stm_ti1.0: driver exit\n");
+	stm_unregister();
 	stm_ti_clean();
+	pr_info("stm_ti1.0: driver exit\n");
 }
 
 module_init(stm_ti_init);
@@ -775,25 +933,27 @@ MODULE_LICENSE("Dual BSD/GPL");
 /*****************************************************************************
  * Support functions
  *****************************************************************************/
-static struct chn_alloc *find_chn_object(int chn)
+
+/* Assumpti0on this function called with dev.lock mutex already locked */
+static struct chn_alloc *construct_chn_obj(int chn, int chn_num)
 {
-	struct list_head *ptr;
-	struct chn_alloc *chn_obj = NULL;
-	struct chn_alloc *chn_obj_ret = NULL;
+	struct chn_alloc *chn_obj;
 
-	if (mutex_lock_interruptible(&dev.lock))
-		return (struct chn_alloc *)-ERESTARTSYS;
+	chn_obj = kmalloc(sizeof(struct chn_alloc), GFP_KERNEL);
+	if (!chn_obj)
+		return (struct chn_alloc *)-ENOMEM;
 
-	list_for_each(ptr, &dev.chn_list_head) {
-		chn_obj = list_entry(ptr, struct chn_alloc, chn_list_link);
-		if (chn == chn_obj->chn) {
-			chn_obj_ret = chn_obj;
-			break;
-		}
-	}
+	mutex_init(&chn_obj->chn_lock);
+	chn_obj->chn = chn;
+	chn_obj->chn_num = chn_num;
+	chn_obj->msg_format = VENDOR;
+	chn_obj->msg_data_type = STRING;
+	chn_obj->xmit_byte_count = 0;
 
-	mutex_unlock(&dev.lock);
-	return chn_obj_ret;
+	list_add(&chn_obj->chn_list_link, &dev.chn_list_head);
+	dev.user_allocated_chn_cnt += chn_num;
+
+	return chn_obj;
 }
 
 static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
@@ -801,7 +961,7 @@ static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
 {
 	/* Parse the set header command */
 	int i;
-	int ret;
+	int ret = 0;
 	char **item = &kbuf;
 	/* Get command - throw it away */
 	char *param = strsep(item, delims);
@@ -811,16 +971,20 @@ static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
 		param = strsep(item, delims);
 		if (!param)
 			return -EINVAL;
-
+#if (LINUX_VERSION_CODE == 132643) /*2.6.35*/
+		ret = strict_strtol(param, 0, &data[i]);
+#else
 		ret = kstrtol(param, 10, &data[i]);
+#endif
 		if (ret)
 			return ret;
 
+
 		if (data[i] < 0 || data[i] > max_ulong)
 			return -EINVAL;
 	}
 
-	return 0;
+	return ret;
 }
 
 static inline uint32_t compose_address(uint32_t addr_type, int32_t stm_chn)
@@ -852,8 +1016,8 @@ static void build_ost_header(uint32_t protocol_id, uint32_t size,
 static int32_t stm_put_msg(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
 			   uint32_t msg_size, int32_t stm_chn, bool timestamp)
 {
-	volatile void * __restrict msg_address;
-	volatile void * __restrict end_address;
+	void *__restrict msg_address;
+	void *__restrict end_address;
 	uint32_t msg_buf_alignemnt;
 	uint32_t hdr_wrd_cnt;
 	uint16_t *short_address;
@@ -941,6 +1105,79 @@ static int32_t stm_put_msg(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
 	return 0;
 }
 
+static int32_t stm_put_bin(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
+			      enum msg_data_t element_type, uint32_t num_bytes,
+					       int32_t stm_chn, bool timestamp)
+{
+	void *__restrict msg_address;
+	void *__restrict end_address;
+	int i;
+	uint8_t *__restrict pmsg_byte = (uint8_t *)pmsg_buf;
+	uint16_t *__restrict pmsg_short = (uint16_t *)pmsg_buf;
+	uint32_t *__restrict pmsg_word = (uint32_t *)pmsg_buf;
+
+	if (!num_bytes)
+		return 0;
+
+	msg_address = (void *)compose_address(STM_REGULAR, stm_chn);
+	if (true == timestamp)
+		end_address = (void *)compose_address(STM_TIMESTAMP, stm_chn);
+	else
+		end_address = msg_address;
+
+	/* If the header pointer is not null and the header
+	 * word count is greater than 0, send the header.
+	 * Else (header word count 0 or header pointer null)
+	 * then it's assumed the header is contained in the message.
+	 */
+	if (hdr_size && phdr_buf) {
+		uint32_t hdr_wrd_cnt = hdr_size/STM_WORD_SIZE;
+		while (hdr_wrd_cnt--) {
+			iowrite32(*(uint32_t *)phdr_buf++,
+						      (uint32_t *)msg_address);
+		}
+	}
+
+	switch (element_type) {
+	case BIN8:
+	{
+		i = num_bytes - 1;
+
+		while (i--)
+			iowrite8(*pmsg_byte++, (uint8_t *)msg_address);
+
+		iowrite8(*pmsg_byte, (uint8_t *)end_address);
+
+		break;
+	}
+	case BIN16:
+	{
+		i = num_bytes/2 - 1;
+
+		while (i--)
+			iowrite16(*pmsg_short++, (uint16_t *)msg_address);
+
+		iowrite16(*pmsg_short, (uint16_t *)end_address);
+
+		break;
+	}
+	case BIN32:
+	{
+		i = num_bytes/4 - 1;
+
+		while (i--)
+			iowrite32(*pmsg_word++, (uint32_t *)msg_address);
+
+		iowrite32(*pmsg_word, (uint32_t *)end_address);
+
+		break;
+	}
+	default:
+		break;
+	}
+
+	return 0;
+}
 static bool stm_app_ownership(void)
 {
 	uint32_t control;
-- 
1.7.0.4

