From: wurui <wu...@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

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to