[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