[linux-yocto] [PATCH 11/65] misc: add owl misc-info driver

Jiang Lu lu.jiang at windriver.com
Wed Dec 21 01:16:12 PST 2016


From: wurui <wurui at actions-semi.com>

commit 2f8ff0630784e6ec5af114f8945ff159a8996fd5 from
https://github.com/xapp-le/kernel.git

Change-Id: I288a6e5444b9850f9481347a365b8997085ce373
---
 drivers/misc/Kconfig               |    1 +
 drivers/misc/Makefile              |    1 +
 drivers/misc/misc-info/Kconfig     |   16 +
 drivers/misc/misc-info/Makefile    |    9 +
 drivers/misc/misc-info/mi_debug.c  |  388 +++++++++++++
 drivers/misc/misc-info/misc_info.c | 1106 ++++++++++++++++++++++++++++++++++++
 drivers/misc/misc-info/misc_info.h |  110 ++++
 7 files changed, 1631 insertions(+)
 mode change 100644 => 100755 drivers/misc/Kconfig
 mode change 100644 => 100755 drivers/misc/Makefile
 create mode 100755 drivers/misc/misc-info/Kconfig
 create mode 100755 drivers/misc/misc-info/Makefile
 create mode 100755 drivers/misc/misc-info/mi_debug.c
 create mode 100755 drivers/misc/misc-info/misc_info.c
 create mode 100755 drivers/misc/misc-info/misc_info.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
old mode 100644
new mode 100755
index b3c10b7..f6bcd7d
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -528,4 +528,5 @@ source "drivers/misc/mic/Kconfig"
 source "drivers/misc/genwqe/Kconfig"
 source "drivers/misc/echo/Kconfig"
 source "drivers/misc/cxl/Kconfig"
+source "drivers/misc/misc-info/Kconfig"
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
old mode 100644
new mode 100755
index 7d5c4cd..8af3148
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
+obj-$(CONFIG_MISC_INFO)		+= misc-info/
\ No newline at end of file
diff --git a/drivers/misc/misc-info/Kconfig b/drivers/misc/misc-info/Kconfig
new file mode 100755
index 0000000..ec360c4
--- /dev/null
+++ b/drivers/misc/misc-info/Kconfig
@@ -0,0 +1,16 @@
+#
+# ACTIONS's MISC INFO ACCESS driver for save important data like serial num,
+# wifi mac etc.
+#
+menu "ACTIONS MISC INFO ACCESS DRIVER"
+config MISC_INFO
+	tristate "Misc info access driver"
+	default y
+	help
+	  The Misc info access driver save the hardware information like
+	  serial no, wifi mac etc.
+	  Each function can be configured and enabled/disabled
+	  dynamically from userspace through a debugfs interface.
+
+	  If unsure, say "y".
+endmenu
diff --git a/drivers/misc/misc-info/Makefile b/drivers/misc/misc-info/Makefile
new file mode 100755
index 0000000..b711b93
--- /dev/null
+++ b/drivers/misc/misc-info/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for ACTIONS's misc info access driver
+# 
+#
+
+EXTRA_CFLAGS  += -DOS_LINUX
+
+obj-$(CONFIG_MISC_INFO) += mi.o
+mi-objs		:= misc_info.o mi_debug.o
diff --git a/drivers/misc/misc-info/mi_debug.c b/drivers/misc/misc-info/mi_debug.c
new file mode 100755
index 0000000..c62d60c
--- /dev/null
+++ b/drivers/misc/misc-info/mi_debug.c
@@ -0,0 +1,388 @@
+
+#ifdef OS_LINUX
+#include <linux/debugfs.h>
+#include "misc_info.h"
+#endif
+
+
+int debug_enable = 0;
+
+#ifdef OS_LINUX
+struct dentry *dirent;
+struct dentry *file;
+
+typedef void (*debug_func_t)(char *param);
+typedef struct
+{
+    char            *func_name;
+    char            *param;
+    debug_func_t     func;
+} struct_debug_func;
+
+
+extern int read_storage(void *buf, int start, int size);
+extern int write_storage(void *buf, int start, int size);
+extern int format_misc_info(void);
+extern int read_mi_head(misc_info_head_t * head);
+extern void print_mi_items(misc_info_head_t * head);
+extern int get_item_size(misc_info_head_t * head, char *name);
+extern int read_mi_item(char *name, void *buf, unsigned int count);
+extern int write_mi_item(char *name, void *buf, unsigned int count);
+
+static void debug_help(char *param);
+static void debug_print(char *param);
+static void debug_dump(char *param);
+static void debug_format(char *param);
+static void debug_print_items(char *param);
+static void debug_get_item(char *param);
+static void debug_set_item(char *param);
+
+struct_debug_func debug_func_table[] =
+{
+    {
+        "help",
+        "",
+        debug_help,
+    },
+	{
+        "print",
+        "enable",
+        debug_print,
+    },
+	{
+        "format",
+        "",
+        debug_format,
+    },
+	{
+		"dump_mem",
+		"start size",
+		debug_dump,
+	},
+	{
+        "print_items",
+        "",
+        debug_print_items,
+    },
+    {
+        "read_item",
+        "name",
+        debug_get_item,
+    },
+	{
+        "write_item",
+        "name type value  type:C/c(char) or H/h(hex), value:length < 200",
+        debug_set_item,
+    },
+};
+
+static void debug_help(char *param)
+{
+    int i;
+    PRINT_DBG("%s, line %d\n",__FUNCTION__, __LINE__);
+	
+    for(i = 0; i < sizeof(debug_func_table)/sizeof(struct_debug_func); i++)
+    {
+        PRINT("[%d] %s %s\n", i, debug_func_table[i].func_name, debug_func_table[i].param);
+    }
+}
+
+static void debug_print(char *param)
+{
+	int enable = 0;
+	
+	PRINT_DBG("%s, line %d\n",__FUNCTION__, __LINE__);
+	sscanf(param, "%d", &enable);
+
+	if(enable == 0 || enable == 1){
+		debug_enable = enable;
+	}else{
+		PRINT_ERR("invalid param\n");
+		return;
+	}
+}
+
+static void debug_dump(char *param)
+{
+	int start = 0, size = 0;
+	unsigned char *buf;
+	
+	PRINT_DBG("%s, line %d\n",__FUNCTION__, __LINE__);
+	sscanf(param, "%d %d", &start, &size);
+	PRINT_DBG("dump memory start %d, size %d\n", start, size);
+	if(start < 0 || size < 0 || (start + size) > MISC_INFO_MAX_SIZE){
+		PRINT_ERR("invalid param\n");
+		return;
+	}
+
+	buf = MALLOC(size);
+	if(!buf){
+		PRINT_ERR("MALLOC FAILED\n");
+		return;
+	}
+	if(read_storage(buf, start, size) < 0){
+		PRINT_ERR("read_storage failed\n");
+		goto OUT;
+	}
+	dump_mem(buf, 0, size);
+OUT:
+	if(buf){
+		FREE(buf);
+		buf = NULL;
+	}
+}
+
+static void debug_format(char *param)
+{
+	PRINT_DBG("%s, line %d\n",__FUNCTION__, __LINE__);
+	format_misc_info();
+}
+
+static void debug_print_items(char *param)
+{
+	misc_info_head_t *head;
+	int head_length;
+	
+	PRINT_DBG("%s, line %d\n",__FUNCTION__, __LINE__);
+	head_length = sizeof(misc_info_head_t);
+	head = MALLOC(head_length);
+	memset(head, 0, head_length);
+	
+	if(read_mi_head(head) < 0){
+		PRINT_ERR("read Head failed\n");
+		return;
+	}
+	print_mi_items(head);
+	
+	if(head){
+		FREE(head);
+		head = NULL;
+	}
+}
+
+static void debug_get_item(char *param)
+{
+    char name[8] = {0};
+	int head_length, size, ret = -1;
+	void *buf;
+	misc_info_head_t *head;
+	
+    sscanf(param, "%s", name);
+	if(name[7] != 0)
+		name[7] = 0;
+	PRINT_DBG("%s, line %d, name %s\n",__FUNCTION__, __LINE__, name);
+	
+	head_length = sizeof(misc_info_head_t);
+	head = MALLOC(head_length);
+	memset(head, 0, head_length);
+	
+	if(read_mi_head(head) < 0){
+		PRINT_ERR("read Head failed\n");
+		goto OUT_FAILED;
+	}
+	size = get_item_size(head, name);
+	if(size <= 0){
+		PRINT_ERR("no item named %s\n",name);
+		goto OUT_FAILED;
+	}
+	buf = MALLOC(size);
+	memset(buf, 0, size);
+	ret = read_mi_item(name, buf, size);
+	if(ret < 0){
+		PRINT_ERR("read data failed\n");
+	}else{
+		dump_mem(buf, 0, ret);
+	}
+	
+	if(buf){
+		FREE(buf);
+		buf = NULL;
+	}
+	
+OUT_FAILED:
+	if(head){
+		FREE(head);
+		head = NULL;
+	}
+}
+
+int check_hex(char *buf)
+{
+	int i;
+	for(i = 0; i < strlen(buf); i++){
+		if((buf[i] >= '0' && buf[i] <= '9')
+			|| (buf[i] >= 'a' && buf[i] <= 'f')
+			|| (buf[i] >= 'A' && buf[i] <= 'F')){
+				continue;
+		}else{
+			return -1;
+		}
+	}
+	return 0;
+}
+
+void char_to_hex(char *in, char *out)
+{
+	int i;
+	char tmp = 0, value = 0;
+	char buf[128] = {0};
+	
+	//printk("%s, strlen(in)=%d\n",__FUNCTION__, (int)strlen(in));
+	if(strlen(in) % 2 == 1){
+		PRINT_ERR("must be divide 2\n");
+		return;
+	} 
+	for(i = 0; i < strlen(in); i++){
+		if(in[i] >= '0' && in[i] <= '9')
+			tmp = in[i] - '0';
+		else if(in[i] >= 'a' && in[i] <= 'f')
+			tmp = in[i] - 'a' + 10;
+		else if(in[i] >= 'A' && in[i] <= 'F')
+			tmp = in[i] - 'A' + 10;
+		
+		if(i % 2 == 0){
+			value = tmp * 16;
+		}else{
+			value += tmp;
+			buf[i/2] = value;
+		}
+	}
+	memcpy(out, buf, strlen(in)/2);
+}
+
+static void debug_set_item(char *param)
+{
+    char name[8] = {0};
+	int ret = -1;
+	char type;
+	char value[256] = {0}, buf[256] = {0};
+	
+    sscanf(param, "%s %c %s", name, &type, value);
+	PRINT_DBG("%s, line %d\n",__FUNCTION__, __LINE__);
+    PRINT_DBG("name %s, type %c, value %s\n", name, type, value);
+	
+	if(type == 'H' || type == 'h'){
+		if(check_hex(value) < 0){
+			PRINT_ERR("err, has invalid hex\n");
+			return;
+		}
+		char_to_hex(value, buf);
+		ret = strlen(value) / 2;//!!!not strlen(buf), because aa00 can be turn to aa.
+	}else if(type == 'C' || type == 'c'){
+		memcpy(buf, value, strlen(value));
+		ret = strlen(value);
+	}else{
+		PRINT_ERR("invalid type %c\n", type);
+		return;
+	}
+	//dump_mem(buf, 0, ret);
+	
+	ret = write_mi_item(name, buf, ret);
+	if(ret < 0){
+		PRINT_ERR("read data failed\n");
+	}
+}
+
+static ssize_t mi_debug_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+    char cmd[512] = {0};
+    char func_name[32] = {0};
+    char param[256] = {0};
+	
+    char *cmd_ptr, *param_ptr;
+    int i, len, flag;
+    
+//	printk("%s, line %d\n",__FUNCTION__, __LINE__);
+	
+    if(copy_from_user(cmd, buf, size))
+    {
+        PRINT_ERR("%s %d, copy_from_user has wrong\n", __FUNCTION__, __LINE__);
+    }
+//    printk("cmd %s\n", cmd);
+	
+    for(i = 0; i < size; i++)
+    {
+        if(cmd[i] == '\n')
+        {
+            cmd[i] = 0;
+            break;
+        }
+    }
+    
+    len = strlen(cmd);
+    flag = 0;
+    for(i = 0; i < len; i++)
+    {
+		if(cmd[i] != ' '){
+			flag = 1;
+		}
+        else if(flag == 1)
+        {
+            memcpy(func_name, cmd, i);
+            func_name[i] = 0;
+			break;
+        }
+    }
+    if(i == len)
+        strcpy(func_name, cmd);
+        
+    PRINT_DBG("func_name=%s\n", func_name);
+    
+    if(i != len)
+    {
+        cmd_ptr = cmd + i + 1;
+        param_ptr = param;
+        len = strlen(cmd_ptr);
+        for(i = 0; i < len; i++)
+        {
+			if(cmd_ptr[i] != ' '){
+				*param_ptr++ = cmd_ptr[i];
+			}
+			else if(param_ptr > param && *(param_ptr-1) != ' ')
+			{
+				*param_ptr++ = ' ';
+			}
+        }
+        *param_ptr = 0;
+        PRINT_DBG("param=%s\n", param);
+    }
+
+    for(i = 0; i < sizeof(debug_func_table)/sizeof(struct_debug_func); i++)
+    {
+        if(strcmp(func_name, debug_func_table[i].func_name) == 0 )
+        {
+            (debug_func_table[i].func)(param);
+            break;
+        }
+    }
+    
+    if(i == sizeof(debug_func_table)/sizeof(struct_debug_func))
+    {
+        PRINT_ERR("can not find function %s\n", func_name);
+    }
+    return size;
+}
+
+static const struct file_operations mi_op = {
+    .write = mi_debug_write,
+};
+
+int mi_debug_init(void)
+{
+	PRINT("%s, line %d\n",__FUNCTION__, __LINE__);
+	dirent = debugfs_create_dir("misc_info", NULL);
+    file = debugfs_create_file("debug", S_IFREG | S_IRUGO, dirent, NULL, &mi_op);
+    
+    return 0;
+}
+
+int mi_debug_exit(void)
+{   
+	PRINT("%s, line %d\n",__FUNCTION__, __LINE__);
+	debugfs_remove(file);
+    debugfs_remove(dirent);
+    return 0;     
+}
+
+#endif
+
diff --git a/drivers/misc/misc-info/misc_info.c b/drivers/misc/misc-info/misc_info.c
new file mode 100755
index 0000000..6946f56
--- /dev/null
+++ b/drivers/misc/misc-info/misc_info.c
@@ -0,0 +1,1106 @@
+/*
+ * Misc info Access driver
+ *
+ * Copyright 2015 Actions Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ *
+ * The driver is used to save the important device hardware information,
+ * ie. Serial No, HDCP Key and etc.
+ * The misc info area is 1M Byte, start from 4M to 5M in storage like
+ * NandFlash or e-MMC and etc.
+ * The driver has 2 copy, one is in kernel, the other is in u-boot.
+ *
+ * Author:  Alex Sun
+ *          28 Aug 2015
+ */
+
+#ifdef OS_LINUX
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/capability.h>
+#include <linux/compat.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#else
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/owl_afi.h>
+#endif
+
+#include "misc_info.h"
+
+int read_misc_info(void *buf, unsigned int count);
+int write_misc_info(void *buf, unsigned int count);
+
+#ifdef OS_LINUX
+extern int mi_debug_init(void);
+extern int mi_debug_exit(void);
+
+const char *mi_file[4]=
+{
+	"/dev/nand0",
+	"/dev/block/nand0",
+	"/dev/mmcblk0",
+	"/dev/block/mmcblk0"
+};
+
+/*
+ * get checksum on the base of 2 bytes
+ */
+static unsigned short get_checksum(unsigned short *buf,unsigned int len)
+{
+	unsigned int loop;
+	unsigned short sum = 0;
+
+	if(!buf || len == 0)
+		return 0;
+
+	for(loop = 0; loop <len; loop++){
+		sum += buf[loop];
+	}
+	sum ^= (unsigned short)0x55aa;
+
+	return sum;
+}
+
+/*
+ * read storage
+ *
+ * 1.ret < 0  read fail
+ * 2.ret >= 0 read success, ret is read length
+ * 3.
+ */
+int read_storage(void *buf, int start, int size)
+{
+	int i, ret = -1;
+	off_t offset;
+	int count;
+	mm_segment_t old_fs;
+	struct file *file = NULL;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, start %d, size %d\n",__FUNCTION__, __LINE__, buf, start, size);
+	if(!buf || size <= 0){
+		PRINT_ERR("invalid param\n");
+		goto OUT;
+	}
+	old_fs = get_fs();
+    set_fs(get_ds());
+
+	for(i = 0; i < 4; i++){
+		file = filp_open(mi_file[i], O_RDONLY, 0);
+		if (IS_ERR(file) || file->f_op == NULL){
+			if(!IS_ERR(file))
+				filp_close(file, NULL);
+			if(i < 3){
+				continue;
+			}else{
+				PRINT_ERR("no blk dev\n");
+				ret = -EAGAIN;
+				goto OUT;
+			}
+		}else{
+			PRINT_DBG("open file %s success\n", mi_file[i]);
+			break;
+		}
+	}
+	offset = file->f_op->llseek(file, (MISC_INFO_OFFSET + start), 0);
+	if(offset != (MISC_INFO_OFFSET + start)){
+		PRINT_ERR("lseek failed, offset %d\n", (int)offset);
+		ret = -1;
+		goto OUT;
+	}
+	count = vfs_read(file, (unsigned char *)buf, size, &file->f_pos);
+	//dump_mem(buf, 0, count);
+    if(count != size)
+    {
+        PRINT_ERR("should read %d, but only read %d!\n", size, count);
+    }
+	PRINT_DBG("read count:%d\n", count);
+	ret = count;
+
+	filp_close(file, NULL);
+    set_fs(old_fs);
+
+OUT:
+	return ret;
+}
+
+/*
+ * write storage
+ *
+ * 1.ret < 0  write fail
+ * 2.ret >= 0 write success, ret is write length
+ * 3.
+ */
+int write_storage(void *buf, int start, int size)
+{
+	int i, ret = -1;
+	off_t offset;
+	int count;
+	mm_segment_t old_fs;
+	struct file *file = NULL;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, start %d, size %d\n",__FUNCTION__, __LINE__, buf, start, size);
+	if(!buf || size <= 0){
+		PRINT_ERR("invalid param\n");
+		goto OUT;
+	}
+
+	old_fs = get_fs();
+    set_fs(get_ds());
+
+	for(i = 0; i < 4; i++){
+		file = filp_open(mi_file[i], O_RDWR, 0);
+		if (IS_ERR(file) || file->f_op == NULL || file->f_op->write == NULL){
+			if(!IS_ERR(file))
+				filp_close(file, NULL);
+			if(i < 3){
+				continue;
+			}else{
+				PRINT_ERR("no blk dev\n");
+				ret = -EAGAIN;
+				goto OUT;
+			}
+		}else{
+			PRINT_DBG("open file %s success\n", mi_file[i]);
+			break;
+		}
+	}
+
+	offset = file->f_op->llseek(file, (MISC_INFO_OFFSET + start), 0);
+	if(offset != (MISC_INFO_OFFSET + start)){
+		PRINT_ERR("lseek failed, offset %d\n", (int)offset);
+		ret = -1;
+		goto OUT;
+	}
+	count = file->f_op->write(file, (unsigned char *)buf, size, &file->f_pos);
+	//dump_mem(buf, 0, count);
+    if(count != size)
+    {
+        PRINT_ERR("should write %d, but only write %d!\n", size, count);
+    }
+	PRINT_DBG("write count:%d\n", count);
+	ret = count;
+
+	filp_close(file, NULL);
+    set_fs(old_fs);
+
+OUT:
+	return ret;
+}
+
+#else
+
+#define BLOCK_SIZE 				 512
+
+extern int owl_get_boot_dev(void);
+extern int LDL_DeviceOpReadSectors(unsigned int start, unsigned int nsector, void *buf, int diskNo);
+extern int LDL_DeviceOpWriteSectors(unsigned int start, unsigned int nsector, void *buf, int diskNo);
+extern ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst);
+extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src);
+
+static int blk_read(void *buf, unsigned int start, unsigned int blkcnt)
+{
+	int ret = -1;
+
+	ret = owl_get_boot_dev();
+	if(ret == OWL_BOOTDEV_NAND){
+//		ret = LDL_DeviceOpReadSectors(start, blkcnt, buf, 0);
+	}else{
+		if(ret == OWL_BOOTDEV_SD0)
+			ret = mmc_bread(0, start, blkcnt, buf);
+		else if(ret == OWL_BOOTDEV_SD2)
+			ret = mmc_bread(1, start, blkcnt, buf);
+		else
+			ret = -1;
+		if(ret != blkcnt)
+			ret = -1;
+		else
+			ret = 0;
+	}
+	return ret;
+}
+
+static int blk_write(void *buf, unsigned int start, unsigned int blkcnt)
+{
+	int ret = -1;
+
+	ret = owl_get_boot_dev();
+	if(ret == OWL_BOOTDEV_NAND){
+//		ret = LDL_DeviceOpWriteSectors(start, blkcnt, buf, 0);
+	}else{
+		if(ret == OWL_BOOTDEV_SD0)
+			ret = mmc_bwrite(0, start, blkcnt, buf);
+		else if(ret == OWL_BOOTDEV_SD2)
+			ret = mmc_bwrite(1, start, blkcnt, buf);
+		else
+			ret = -1;
+		if(ret != blkcnt)
+			ret = -1;
+		else
+			ret = 0;
+	}
+	return ret;
+}
+
+/*
+ * read storage
+ *
+ * 1.ret < 0  read fail
+ * 2.ret >= 0 read success, ret is read length
+ * 3.
+ */
+int read_storage(void *buf, int start, int size)
+{
+	int start_blk, start_in_blk, count;
+	char *blk_buf;
+	int ret = size;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, start %d, size %d\n",__FUNCTION__, __LINE__, buf, start, size);
+
+	if(!buf || size <= 0){
+		PRINT_ERR("invalid param\n");
+		ret = -1;
+		goto OUT_NULL;
+	}
+
+	blk_buf = MALLOC(BLOCK_SIZE);
+	if(!blk_buf){
+		PRINT_ERR("MALLOC FAILED\n");
+		ret = -ENOMEM;
+		goto OUT_NULL;
+	}
+	memset(blk_buf, 0, BLOCK_SIZE);
+
+	if(start % BLOCK_SIZE != 0){
+		start_in_blk = (MISC_INFO_OFFSET + start) % BLOCK_SIZE;
+		start_blk = (MISC_INFO_OFFSET + start) / BLOCK_SIZE;//from sector 0
+		if(blk_read(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_read failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		count = size > (BLOCK_SIZE - start_in_blk) ? (BLOCK_SIZE - start_in_blk) : size;
+		memcpy(buf, blk_buf + start_in_blk, count);
+		buf += count;
+		start += count;
+		size -= count;
+	}
+	while(size > BLOCK_SIZE){
+		start_blk = (MISC_INFO_OFFSET + start) / BLOCK_SIZE;//from sector 0
+		if(blk_read(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_read failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		memcpy(buf, blk_buf, BLOCK_SIZE);
+		buf += BLOCK_SIZE;
+		start += BLOCK_SIZE;
+		size -= BLOCK_SIZE;
+	}
+	if(size > 0){
+		start_blk = (MISC_INFO_OFFSET + start) / BLOCK_SIZE;//from sector 0
+		if(blk_read(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_read failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		memcpy(buf, blk_buf, size);
+	}
+
+OUT_FAILED:
+	if(blk_buf){
+		FREE(blk_buf);
+		blk_buf = NULL;
+	}
+OUT_NULL:
+	return ret;
+}
+/*
+ * write storage
+ *
+ * 1.ret < 0  write fail
+ * 2.ret >= 0 write success, ret is write length
+ * 3.
+ */
+int write_storage(void *buf, int start, int size)
+{
+	int start_blk, start_in_blk, count;
+	char *blk_buf;
+	int ret = size;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, start %d, size %d\n",__FUNCTION__, __LINE__, buf, start, size);
+
+	if(!buf || size <= 0){
+		PRINT_ERR("invalid param\n");
+		ret = -1;
+		goto OUT_NULL;
+	}
+
+	blk_buf = MALLOC(BLOCK_SIZE);
+	if(!blk_buf){
+		PRINT_ERR("MALLOC FAILED\n");
+		ret = -ENOMEM;
+		goto OUT_NULL;
+	}
+	memset(blk_buf, 0, BLOCK_SIZE);
+
+	if(start % BLOCK_SIZE != 0){
+		start_in_blk = (MISC_INFO_OFFSET + start) % BLOCK_SIZE;
+		start_blk = (MISC_INFO_OFFSET + start) / BLOCK_SIZE;//from sector 0
+		if(blk_read(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_read failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		count = size > (BLOCK_SIZE - start_in_blk) ? (BLOCK_SIZE - start_in_blk) : size;
+		memcpy(blk_buf + start_in_blk, buf, count);
+		if(blk_write(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_write failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		buf += count;
+		start += count;
+		size -= count;
+	}
+	while(size > BLOCK_SIZE){
+		start_blk = (MISC_INFO_OFFSET + start) / BLOCK_SIZE;//from sector 0
+		memcpy(blk_buf, buf, BLOCK_SIZE);
+		if(blk_write(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_write failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		buf += BLOCK_SIZE;
+		start += BLOCK_SIZE;
+		size -= BLOCK_SIZE;
+	}
+	if(size > 0){
+		start_blk = (MISC_INFO_OFFSET + start) / BLOCK_SIZE;//from sector 0
+		if(blk_read(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_read failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		memcpy(blk_buf, buf, size);
+		if(blk_write(blk_buf, start_blk, 1) < 0){
+			PRINT_ERR("blk_write failed, start blk %d, blkcnt 1\n", start_blk);
+			ret = -1;
+			goto OUT_FAILED;
+		}
+	}
+
+OUT_FAILED:
+	if(blk_buf){
+		FREE(blk_buf);
+		blk_buf = NULL;
+	}
+OUT_NULL:
+	return ret;
+}
+#endif
+
+
+/*
+ * read misc info head
+ *
+ * 1.ret < 0  read fail
+ * 2.ret == 0 read data invalid
+ * 3.ret > 0  read success
+ */
+int read_mi_head(misc_info_head_t * head)
+{
+	int ret, head_length;
+	misc_info_head_t *tmp_head = NULL;
+	char *head_buf = NULL;
+
+	PRINT_DBG("%s, line %d\n",__func__, __LINE__);
+	head_length = sizeof(misc_info_head_t);
+	head_buf = MALLOC(head_length);
+	if(!head_buf){
+		PRINT_ERR("MALLOC head failed\n");
+		ret = -ENOMEM;
+		goto OUT_NULL;
+	}
+	memset(head_buf, 0, head_length);
+
+	ret = read_storage(head_buf, 0, head_length);
+	if(ret < 0){
+		PRINT_ERR("read MiscInfoHeader failed\n");
+		goto OUT_FAILED;
+	}
+	if(ret != head_length){
+		PRINT_ERR("read_storage return %d, but should be %d\n", ret, head_length);
+		goto OUT_FAILED;
+	}
+	tmp_head = (misc_info_head_t *)head_buf;
+	if(tmp_head->magic != MISC_INFO_MAGIC || tmp_head->length > MISC_INFO_MAX_SIZE
+		|| tmp_head->item_num > MISC_INFO_MAX_ITEM_NUM){
+		PRINT_ERR("%s, line %d, magic 0x%x, length %d, item num %d\n", __FUNCTION__, __LINE__,
+			tmp_head->magic, tmp_head->length, tmp_head->item_num);
+		ret = 0;
+		goto OUT_FAILED;
+	}
+	memcpy(head, (misc_info_head_t *)head_buf, head_length);
+	ret = head_length;
+	if(debug_enable)
+		dump_mem(head, 0, head_length);
+
+OUT_FAILED:
+	if(head_buf){
+		FREE(head_buf);
+		head_buf = NULL;
+	}
+OUT_NULL:
+	return ret;
+}
+
+/*
+ * read misc info item
+ *
+ * 1.ret < 0  read fail
+ * 2.ret > 0  read success, ret is read length
+ *
+ */
+int read_mi_item(char *name, void *buf, unsigned int count)
+{
+	int ret = -1, item;
+	unsigned short chksum_calc, chksum_rec;
+	misc_info_head_t *head = NULL;
+	unsigned char *data = NULL;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, count %d\n", __func__, __LINE__, buf, count);
+	if(!name || !buf || count == 0){
+		PRINT_ERR("%s, line %d, err\n", __func__, __LINE__);
+		goto OUT_NULL;
+	}
+
+	head = MALLOC(sizeof(misc_info_head_t));
+	if(!head){
+		PRINT_ERR("MALLOC head failed\n");
+		ret = -ENOMEM;
+		goto OUT_NULL;
+	}
+	memset(head, 0, sizeof(misc_info_head_t));
+
+	ret = read_mi_head(head);
+	if(ret < 0){
+		PRINT_ERR("read Head failed\n");
+		goto OUT_FAILED;
+	}else if(ret == 0){
+		PRINT_ERR("read Head null\n");
+		ret = -1;
+		goto OUT_FAILED;
+	}
+	PRINT_DBG("%s, line %d, misc info: length %d, item num %d\n", __func__, __LINE__, head->length, head->item_num);
+
+	if(strlen(name) > sizeof(head->item_head[0].name)){
+		PRINT_ERR("invalid name, too large\n");
+		goto OUT_FAILED;
+	}
+	for(item = 0; item < head->item_num; item++)
+	{
+		if(memcmp(name, head->item_head[item].name, strlen(name)) == 0){
+			break;
+		}
+	}
+	if(item == head->item_num){
+		PRINT_ERR("can not find %s\n", name);
+		goto OUT_FAILED;
+	}
+	PRINT_DBG("%s, line %d, name %s, size %d, offset %d, checksum 0x%x\n", __func__, __LINE__,
+	 head->item_head[item].name, head->item_head[item].size,
+	 head->item_head[item].offset, head->item_head[item].chk_sum);
+
+	data = MALLOC(head->item_head[item].size);
+	if(!data){
+		PRINT_ERR("MALLOC head failed\n");
+		ret = -ENOMEM;
+		goto OUT_FAILED;
+	}
+	memset(data, 0, head->item_head[item].size);
+	ret = read_storage(data, head->item_head[item].offset, head->item_head[item].size);
+	if(ret < 0){
+		PRINT_ERR("read item %s data failed\n", name);
+		goto OUT_FAILED;
+	}
+	if(debug_enable)
+		dump_mem(data, 0, head->item_head[item].size);
+	chksum_rec = head->item_head[item].chk_sum;
+	chksum_calc = get_checksum((unsigned short *)data, head->item_head[item].size/2);
+	if(chksum_rec != chksum_calc)
+	{
+		PRINT_ERR("get %s chksum failed, calc:0x%x rec:0x%x\n", name, chksum_calc, chksum_rec);
+		//dump_mem(data, 0, head->item_head[item].size);
+		ret = -1;
+		goto OUT_INVALID;
+	}
+	ret = (count > head->item_head[item].size) ? head->item_head[item].size : count;
+	memcpy(buf, data, ret);
+	PRINT("%s, line %d, success\n", __func__, __LINE__);
+
+OUT_INVALID:
+	if(data){
+		FREE(data);
+		data = NULL;
+	}
+OUT_FAILED:
+	if(head){
+		FREE(head);
+		head = NULL;
+	}
+OUT_NULL:
+	return ret;
+}
+
+/*
+ * write misc info item
+ *
+ * 1.ret < 0  write fail
+ * 2.ret >= 0 write success, ret is write length
+ *
+ */
+int write_mi_item(char *name, void *buf, unsigned int count)
+{
+	int ret = -1, pack_len;
+    usb_packet_t *packet = NULL;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, count %d\n", __func__, __LINE__, buf, count);
+	if(!name || !buf || count == 0){
+		PRINT_ERR("%s, line %d, err\n", __func__, __LINE__);
+		goto OUT_NULL;
+	}
+	pack_len = sizeof(int) + sizeof(packet_item_t) + count;
+
+    packet = MALLOC(pack_len);
+	if(!packet){
+		PRINT_ERR("MALLOC packet failed\n");
+		ret = -ENOMEM;
+		goto OUT_NULL;
+	}
+	memset(packet, 0, pack_len);
+
+	packet->length = pack_len;
+	packet->item[0].magic = MISC_INFO_MAGIC;// FIXME
+	if(strlen(name) > sizeof(packet->item[0].name)){
+		PRINT_ERR("invalid name, too large, must < 7 Byte\n");
+		goto OUT_FAILED;
+	}
+	memcpy(packet->item[0].name, name, strlen(name));
+	packet->item[0].size = count;
+	memcpy(packet->item[0].data, buf, count);
+
+	ret = write_misc_info(packet, packet->length);
+	if(ret != packet->length){
+		PRINT_ERR("write item failed, ret %d\n", ret);
+	}
+	PRINT("%s, line %d, success\n", __func__, __LINE__);
+
+OUT_FAILED:
+	if(packet){
+		FREE(packet);
+		packet = NULL;
+	}
+OUT_NULL:
+	return ret;
+}
+
+/*
+ * print all item info
+ *
+ */
+void print_mi_items(misc_info_head_t * head)
+{
+	int item;
+	if(!head){
+		PRINT_ERR("%s, line %d, buf is NULL\n", __func__, __LINE__);
+		return;
+	}
+
+	for(item = 0; item < head->item_num; item++){
+		PRINT("[%02d] name:%s size:%d\n", item, head->item_head[item].name,
+			  head->item_head[item].size);
+	}
+}
+
+/*
+ * get item size
+ *
+ */
+int get_item_size(misc_info_head_t * head, char *name)
+{
+	int ret = -1, item;
+	if(!head || !name){
+		PRINT_ERR("%s, line %d, buf is NULL\n", __func__, __LINE__);
+		return ret;
+	}
+
+	if(strlen(name) > sizeof(head->item_head[0].name)){
+		PRINT_ERR("invalid name, too large, must < 7 Byte\n");
+		return ret;
+	}
+	for(item = 0; item < head->item_num; item++){
+		if(memcmp(head->item_head[item].name, name, strlen(name)) == 0){
+			return head->item_head[item].size;
+		}
+	}
+	return ret;
+}
+
+/*
+ * read misc info
+ *
+ * 1.the data is read to pc tool through USB.
+ * 2.
+ */
+int read_misc_info(void *buf, unsigned int count)
+{
+	int ret = -1, i;
+	int head_length, data_length, pack_length, data_offset;
+	unsigned short chksum_calc, chksum_rec;
+	misc_info_head_t *head = NULL;
+	unsigned char *data = NULL;
+	usb_packet_t *packet = NULL;
+	packet_item_t *item = NULL;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, count %d\n", __func__, __LINE__, buf, count);
+
+	if(!buf){
+		PRINT_ERR("%s, line %d, buf is NULL\n", __func__, __LINE__);
+		return ret;
+	}
+
+	head_length = sizeof(misc_info_head_t);
+	head = MALLOC(head_length);
+	if(!head){
+		PRINT_ERR("MALLOC head failed\n");
+		ret = -ENOMEM;
+		goto MALLOC_FAILED;
+	}
+	memset(head, 0, head_length);
+
+	ret = read_mi_head(head);
+	if(ret < 0){
+		PRINT_ERR("read Head failed\n");
+		ret = -1;
+		goto READ_HEAD_FAILED;
+	}else if(ret == 0){
+		memset(head, 0, head_length);
+	}else{
+		PRINT_DBG("%s, line %d, misc info: length %d, item num %d\n", __func__, __LINE__, head->length, head->item_num);
+		data_length = head->length - head_length;
+		data = MALLOC(data_length);
+		if(!data){
+			PRINT_ERR("MALLOC data failed\n");
+			ret = -ENOMEM;
+			goto READ_HEAD_FAILED;
+		}
+		memset(data, 0, data_length);
+
+		if(read_storage(data, head_length, data_length) < 0){
+			PRINT_ERR("read data failed\n");
+			goto READ_DATA_FAILED;
+		}
+		if(debug_enable)
+			dump_mem(data, 0, data_length);
+	}
+
+	pack_length = sizeof(int);
+	for(i=0; i<head->item_num; i++)
+	{
+		pack_length += sizeof(packet_item_t) + head->item_head[i].size;//sizeof(packet_item_t)==4+8+4?
+	}
+	PRINT_DBG("%s, line %d, packet length %d\n", __func__, __LINE__, pack_length);
+
+	packet = (usb_packet_t *) MALLOC(pack_length);
+	if(!packet){
+		PRINT_ERR("MALLOC packet failed\n");
+		ret = -ENOMEM;
+		goto READ_DATA_FAILED;
+	}
+	memset(packet, 0, pack_length);
+	item = packet->item;
+
+	packet->length = pack_length;
+	for(i=0; i<head->item_num; i++){
+		item->magic = head->item_head[i].magic;
+		memcpy(item->name, head->item_head[i].name, strlen(head->item_head[i].name));
+		item->size = head->item_head[i].size;
+		data_offset = head->item_head[i].offset - head_length;
+		memcpy(item->data, data + data_offset, item->size);
+
+		chksum_rec = head->item_head[i].chk_sum;
+		chksum_calc = get_checksum((unsigned short *)item->data, item->size/2);
+		if(chksum_rec != chksum_calc){
+			PRINT_ERR("get %s chksum failed calc:%x rec:%x\n", item->name, chksum_calc, chksum_rec);
+			//dump_mem(item->data, 0, item->size);
+		}
+		item = (packet_item_t *)((char *)item + sizeof(packet_item_t) + item->size);
+	}
+	dump_mem(packet, 0, packet->length);
+
+	ret = (count > packet->length) ? packet->length : count;
+	memcpy(buf, packet, ret);
+	PRINT("%s, line %d, success\n", __func__, __LINE__);
+
+	if(packet){
+		FREE(packet);
+		packet = NULL;
+	}
+READ_DATA_FAILED:
+	if(data){
+		FREE(data);
+		data = NULL;
+	}
+READ_HEAD_FAILED:
+	if(head){
+		FREE(head);
+		head = NULL;
+	}
+MALLOC_FAILED:
+	return ret;
+}
+
+/*
+ * write misc info
+ *
+ * 1.the data is written from pc tool through USB.
+ * 2.if the data is incomplete, write part of it.
+ * 3.item will be merged, item with same name will override the old.
+ */
+int write_misc_info(void *buf, unsigned int count)
+{
+    int ret = -1, offset = 0, item_size, head_length;
+	int index = 0, pack_item_num, pack_pos, i, j;
+    usb_packet_t *packet = NULL;
+    packet_item_t *pack_item = NULL;
+	misc_info_t *old_misc = NULL, *new_misc = NULL;
+	misc_info_head_t *new_head = NULL, *old_head = NULL;
+	unsigned char *new_data = NULL, *old_data = NULL;
+
+	PRINT_DBG("%s, line %d, buf 0x%p, count %d\n", __FUNCTION__, __LINE__, buf, count);
+	if(buf == NULL){
+		PRINT_ERR("%s, line %d, buf is null\n",__FUNCTION__, __LINE__);
+		return -1;
+	}
+	if(debug_enable)
+		dump_mem(buf, 0, count);
+
+    packet = (usb_packet_t *)buf;
+
+	if(count <= sizeof(int) + sizeof(packet_item_t)){
+		return 0;
+	}
+
+	old_misc = (misc_info_t *) MALLOC(MISC_INFO_MAX_SIZE);
+	if(!old_misc){
+		PRINT_ERR("MALLOC old_misc failed\n");
+		ret = -ENOMEM;
+		goto MALLOC_OLD_MISC_FAILED;
+	}
+	new_misc = (misc_info_t *) MALLOC(MISC_INFO_MAX_SIZE);
+	if(!new_misc){
+		PRINT_ERR("MALLOC new_misc failed\n");
+		ret = -ENOMEM;
+		goto MALLOC_NEW_MISC_FAILED;
+	}
+	memset(old_misc, 0, MISC_INFO_MAX_SIZE);
+	memset(new_misc, 0, MISC_INFO_MAX_SIZE);
+
+    head_length = sizeof(misc_info_head_t);
+	new_head = &new_misc->head;
+	new_data = (char *)new_misc + head_length;////!!!!(char *) is must, so easy to forget
+	PRINT_DBG("new_head 0x%p, new_data 0x%p\n",new_head,new_data);
+
+    pack_item = packet->item;
+    pack_pos = sizeof(packet->length);
+    PRINT_DBG("%s, line %d, length %d\n", __FUNCTION__, __LINE__, packet->length);
+
+	//parse packet
+    while(pack_pos < packet->length)
+	{
+		//check packet data completable
+		if(count < pack_pos + sizeof(packet_item_t) + pack_item->size){
+			PRINT_ERR("%s, line %d, pack_pos %d, sizeof(packet_item_t) %d, pack_item->size %d\n",
+			__FUNCTION__, __LINE__, pack_pos, sizeof(packet_item_t), pack_item->size);
+			break;
+		}
+		new_head->item_head[index].magic = pack_item->magic;
+		memcpy(new_head->item_head[index].name, pack_item->name, strlen(pack_item->name));
+		new_head->item_head[index].size = pack_item->size;
+		new_head->item_head[index].offset = head_length + offset;//offset is from begining
+		offset += new_head->item_head[index].size;
+		new_head->item_head[index].chk_sum = get_checksum((unsigned short *)pack_item->data, pack_item->size/2);
+		//copy
+		memcpy(new_data, pack_item->data, new_head->item_head[index].size);
+		new_data += new_head->item_head[index].size;
+
+		item_size = sizeof(packet_item_t) + pack_item->size;
+        pack_pos += item_size;
+        pack_item = (packet_item_t *)((unsigned char *)pack_item + item_size);
+		index++;
+	}
+	ret = pack_pos;
+	PRINT_DBG("pack_pos %d\n", pack_pos);
+	pack_item_num = index;
+
+	//read misc info to merge with packet data
+	if(read_storage((unsigned char*)old_misc, 0, MISC_INFO_MAX_SIZE) < 0){
+		PRINT_ERR("readMiscInfo failed\n");
+		ret = -1;
+		goto OUT_END;
+	}
+	old_head = &old_misc->head;
+	old_data = (char *)old_misc + head_length;////!!!!(char *) is must, so easy to forget
+	if(old_head->magic != MISC_INFO_MAGIC || old_head->length > MISC_INFO_MAX_SIZE
+		|| old_head->item_num > MISC_INFO_MAX_ITEM_NUM){
+		PRINT_ERR("%s, line %d, magic 0x%x, length %d, item num %d\n", __FUNCTION__, __LINE__,
+			old_head->magic, old_head->length, old_head->item_num);
+		PRINT_ERR("invalid old misc info\n");
+	}else{
+		PRINT_DBG("%s, line %d, old misc info: length %d, item num %d\n", __func__, __LINE__, old_head->length, old_head->item_num);
+		for(i=0; i<old_head->item_num; i++)
+		{
+			for(j=0; j<pack_item_num; j++)
+			{
+				if(memcmp(old_head->item_head[i].name, new_head->item_head[j].name, sizeof(old_head->item_head[i].name)) == 0){
+					break;
+				}
+			}
+			if(j < pack_item_num)
+				continue;
+
+			memcpy(&new_head->item_head[index], &old_head->item_head[i], sizeof(item_head_t));
+			new_head->item_head[index].offset = head_length + offset;
+			offset += new_head->item_head[index].size;
+
+			//copy data
+			//!!!old_misc->data is wrong
+			old_data = (char *)old_misc + old_head->item_head[i].offset;
+			memcpy(new_data, old_data, old_head->item_head[i].size);
+			new_data += new_head->item_head[index].size;
+
+			index++;
+		}
+	}
+
+	//build head
+	new_head->magic = MISC_INFO_MAGIC;
+	new_head->item_num = index;
+	new_head->length = head_length;
+	for(i=0; i<new_head->item_num; i++){
+		new_head->length += new_head->item_head[i].size;
+	}
+	PRINT_DBG("%s, line %d, new misc info: length %d, item num %d\n", __func__, __LINE__, new_head->length, new_head->item_num);
+
+	//check total length
+	if(new_head->length > MISC_INFO_MAX_SIZE){
+		PRINT_ERR("new misc info length > MISC_INFO_MAX_SIZE, do nothing\n");
+		dump_mem(new_misc, 0, new_head->length);
+		ret = -1;
+		goto OUT_END;
+	}
+
+	if(debug_enable)
+		dump_mem(new_misc, 0, new_head->length);
+
+	//write
+	if(write_storage(new_misc, 0, new_head->length) < 0){
+		PRINT_ERR("%s, line %d, write_storage failed\n", __FUNCTION__, __LINE__);
+		ret = -1;
+	}
+	PRINT("%s, line %d, success\n", __func__, __LINE__);
+
+OUT_END:
+MALLOC_NEW_MISC_FAILED:
+	if(new_misc){
+		FREE(new_misc);
+		new_misc = NULL;
+	}
+MALLOC_OLD_MISC_FAILED:
+	if(old_misc){
+		FREE(old_misc);
+		old_misc = NULL;
+	}
+
+	return ret;
+}
+
+int format_misc_info(void)
+{
+	unsigned char *buf = NULL;
+
+	PRINT_DBG("%s, line %d\n",__func__, __LINE__);
+	buf = MALLOC(MISC_INFO_MAX_SIZE);
+	if(!buf){
+		PRINT_ERR("MALLOC buf failed\n");
+		return -ENOMEM;
+	}
+	memset(buf, 0, MISC_INFO_MAX_SIZE);
+
+	if(write_storage(buf, 0, MISC_INFO_MAX_SIZE) < 0){
+		PRINT_ERR("%s, line %d, write_storage failed\n", __func__, __LINE__);
+		return -1;
+	}
+
+	if(buf){
+		FREE(buf);
+		buf = NULL;
+	}
+	PRINT("%s, line %d, success\n", __func__, __LINE__);
+
+	return 0;
+}
+
+#ifdef OS_LINUX
+
+static int mi_open(struct inode *inode, struct file *filp)
+{
+	if(nonseekable_open(inode, filp))
+	{
+		PRINT_ERR ("misc nonseekable_open failed\n");
+		return -1;
+	}
+    return 0;
+}
+
+static int mi_release(struct inode *inode, struct file *filp)
+{
+    return 0;
+}
+
+static long mi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int ret = -1;
+	ioctl_item_t item;
+	char *buf = NULL;
+
+	switch(cmd){
+	case GET_ITEM_DATA:
+		if(copy_from_user(&item, (void*)arg, sizeof(ioctl_item_t)) != 0){
+			PRINT_ERR("copy_from_user failed\n");
+			goto OUT_NULL;
+		}
+		PRINT_DBG("item.name %s, len %d\n", item.name, strlen(item.name));
+		PRINT_DBG("item.size %d\n", item.size);
+		PRINT_DBG("item.data 0x%p\n", item.data);
+
+		buf = MALLOC(item.size);
+		if(!buf){
+			PRINT_ERR("MALLOC buf failed\n");
+			ret = -ENOMEM;
+			goto OUT_NULL;
+		}
+		ret = read_mi_item(item.name, buf, item.size);
+		if(ret <= 0){
+			PRINT_ERR("read_mi_item failed\n");
+			goto OUT_FAILED;
+		}
+		PRINT_DBG("read_mi_item ret %d\n", ret);
+		if(debug_enable)
+			dump_mem(buf, 0, ret);
+		if(copy_to_user(item.data, buf, ret) != 0){
+			PRINT_ERR("copy_to_user failed\n");
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		break;
+	case SET_ITEM_DATA:
+		if(copy_from_user(&item, (void*)arg, sizeof(ioctl_item_t)) != 0){
+			PRINT_ERR("copy_from_user failed\n");
+			goto OUT_NULL;
+		}
+		PRINT_DBG("item.name %s, len %d\n", item.name, strlen(item.name));
+		PRINT_DBG("item.size %d\n", item.size);
+		PRINT_DBG("item.data 0x%p\n", item.data);
+
+		buf = MALLOC(item.size);
+		if(!buf){
+			PRINT_ERR("MALLOC buf failed\n");
+			ret = -ENOMEM;
+			goto OUT_NULL;
+		}
+		if(copy_from_user(buf, item.data, item.size) != 0){
+			PRINT_ERR("copy_from_user failed\n");
+			ret = -1;
+			goto OUT_FAILED;
+		}
+		if(debug_enable)
+			dump_mem(buf, 0, item.size);
+		ret = write_mi_item(item.name, buf, item.size);
+		if(ret < 0){
+			PRINT_ERR("write_mi_item failed\n");
+			goto OUT_FAILED;
+		}
+		break;
+	case FORMAT_MISC_INFO:
+		if(format_misc_info() < 0){
+			PRINT_ERR("format misc info failed\n");
+			ret = -1;
+		}
+		break;
+	}
+	return ret;
+
+OUT_FAILED:
+	if(buf){
+		FREE(buf);
+		buf = NULL;
+	}
+OUT_NULL:
+	return ret;
+}
+
+static struct file_operations mi_fops =
+{
+    .owner   		= THIS_MODULE,
+    .unlocked_ioctl = mi_ioctl,
+    .open    		= mi_open,
+    .release 		= mi_release
+};
+
+static struct miscdevice mi_dev = {
+    .minor = MISC_DYNAMIC_MINOR,
+    .name = "misc_info",
+    .fops = &mi_fops,
+};
+
+static int __init misc_info_init(void)
+{
+	PRINT("%s, line %d\n", __FUNCTION__, __LINE__);
+
+	if(misc_register(&mi_dev) < 0)
+		return -1;
+	mi_debug_init();
+
+	return 0;
+}
+
+static void __exit misc_info_exit(void)
+{
+    PRINT("%s, line %d\n", __FUNCTION__, __LINE__);
+
+	misc_deregister(&mi_dev);
+    mi_debug_exit();
+	return;
+}
+
+module_init(misc_info_init);
+module_exit(misc_info_exit);
+
+EXPORT_SYMBOL_GPL(read_misc_info);
+EXPORT_SYMBOL_GPL(write_misc_info);
+EXPORT_SYMBOL_GPL(format_misc_info);
+EXPORT_SYMBOL_GPL(read_mi_item);
+EXPORT_SYMBOL_GPL(write_mi_item);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex.Sun");
+MODULE_DESCRIPTION("MISC INFO access driver");
+
+#endif
diff --git a/drivers/misc/misc-info/misc_info.h b/drivers/misc/misc-info/misc_info.h
new file mode 100755
index 0000000..a07954e
--- /dev/null
+++ b/drivers/misc/misc-info/misc_info.h
@@ -0,0 +1,110 @@
+#ifndef __MISC_INFO_H_
+#define __MISC_INFO_H_
+
+
+
+#ifdef OS_LINUX
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+
+#define PRINT(x...)                     	printk(x)
+#define PRINT_DBG(x...)						if(debug_enable)printk(x)
+#define PRINT_ERR(x...)						printk(KERN_ERR x)
+#define INFO(x...)
+#define MALLOC(x)                       	kmalloc(x, GFP_KERNEL)
+#define FREE(x)                         	kfree(x)
+
+#else
+#define PRINT(x...)                     	printf(x)
+#define PRINT_DBG(x...)						if(debug_enable)printf(x)
+#define PRINT_ERR(x...)						printf(x)
+#define INFO(x...)
+#define MALLOC(x)                       	malloc(x)
+#define FREE(x)                         	free(x)
+#endif
+
+extern void *malloc(unsigned int size);
+extern void free(void *ptr);
+extern int debug_enable;
+
+#define MISC_INFO_MAGIC          0x55aa55aa
+#define MISC_INFO_OFFSET         4*1024*1024
+#define MISC_INFO_MAX_SIZE       1024*1024
+#define MISC_INFO_MAX_ITEM_NUM   16
+#define MISC_INFO_HEAD_ALIGN     1024
+
+#define GET_ITEM_DATA            0
+#define SET_ITEM_DATA            1
+#define FORMAT_MISC_INFO         2
+
+typedef struct
+{
+  unsigned char          name[8];
+  unsigned int           size;
+  unsigned char          *data; 
+}ioctl_item_t;
+
+typedef struct
+{
+  unsigned int           magic;
+  unsigned char          name[8];
+  unsigned int           size;
+  unsigned char          data[]; 
+}packet_item_t;
+
+typedef struct
+{
+    unsigned int      length;//packet length
+    packet_item_t     item[];
+}usb_packet_t;
+
+
+typedef struct
+{
+	unsigned char  name[8];
+	unsigned int   magic;
+	unsigned short size;		//size of item data
+	unsigned short offset;		//offset from the beginning
+	unsigned short chk_sum;
+	unsigned char  reserved[16];
+}__attribute__((aligned(4)))item_head_t;
+
+typedef struct
+{    
+	unsigned int   magic;
+	unsigned short length;		//total length of misc info
+	unsigned short item_num;	
+	unsigned char  reserved[8];
+	item_head_t item_head[MISC_INFO_MAX_ITEM_NUM];
+}__attribute__((aligned(MISC_INFO_HEAD_ALIGN)))misc_info_head_t;
+
+typedef struct
+{    
+    misc_info_head_t head;
+    unsigned char *data;
+}misc_info_t;
+
+static void dump_mem(void *buf, unsigned int start, unsigned int size)
+{
+	unsigned char *ptr;
+    int i;
+
+	if(!buf){
+		PRINT_ERR("%s, buf is null\n", __FUNCTION__);
+		return;
+	}
+	
+    ptr = (unsigned char *)buf + start;
+    for(i = 0; i < size; i++){
+        if(i % 16 == 0)
+            PRINT("%d: ", start + i);
+        PRINT("%.2x ", *ptr++);
+        if(i % 16 == 15)
+            PRINT("\n");
+    }
+    PRINT("\n");
+}
+
+#endif
-- 
2.7.4



More information about the linux-yocto mailing list