/*****************************************************************************
Description : fastbootlog init
check emmc leaves log to record
if there is log, launch work queue, and create /proc/balong/fastbootlog
History
1.Date: 2012/9/13
Author : x00138766
Modification : Created function
 *****************************************************************************/
static int __init fastbootlog_dump_init(void)
{
	void *fastboot_buff;
	struct fastbootlog_head *head;
	char *start;
	unsigned int size;

#ifndef CONFIG_ARCH_HI3XXX
	if (!himntn_gobal_resetlog) {
		return 0;
	}
#endif

	fastboot_buff = ioremap(FASTBOOT_DUMP_LOG_ADDR, FASTBOOT_DUMP_LOG_SIZE);
	if (!fastboot_buff) {
		printk(KERN_ERR"%s fail to ioremap %#x bytes \n", __func__, FASTBOOT_DUMP_LOG_SIZE);
		return -1;
	}
	
	head = (struct fastbootlog_head *)fastboot_buff;
	start  = (char *)head + sizeof(struct fastbootlog_head);
	size = head->log_offset - sizeof(struct fastbootlog_head);
	if (head->magic==FASTBOOT_MAGIC_1 || head->magic==FASTBOOT_MAGIC_2)
		bootloader_logger_dump(start, size);
	
	fastboot_log_buff = vmalloc(FASTBOOT_DUMP_LOG_SIZE);
	if(!fastboot_log_buff){
		printk(KERN_ERR"%s fail to vmalloc %d bytes \n", __FUNCTION__, FASTBOOT_DUMP_LOG_SIZE);
		return -1;
	}

	memcpy(fastboot_log_buff, fastboot_buff, FASTBOOT_DUMP_LOG_SIZE);
	fastboot_log_size = FASTBOOT_DUMP_LOG_SIZE;
	iounmap(fastboot_buff);
	
	balong_create_log_proc_entry("fastboot", S_IRUGO, &fastbootlog_dump_file_fops, NULL);

	return 0;
}
static int __init fastbootlog_dump_init(void)
{
	char *fastbootlog_buff;
	struct fastbootlog_head *head;
	char *lastlog_start;
	unsigned int lastlog_size;
	char *log_start;
	unsigned int log_size;
	int use_ioremap = 0;
	int need_dump_whole = 0;
	unsigned tmp_len;
	int ret = 0;

	if (!check_himntn(HIMNTN_GOBAL_RESETLOG)) {
		return ret;
	}

	if (pfn_valid(__phys_to_pfn(FASTBOOT_DUMP_LOG_ADDR))) {
		fastbootlog_buff = phys_to_virt(FASTBOOT_DUMP_LOG_ADDR);
	} else {
		use_ioremap = 1;
		fastbootlog_buff =
		    ioremap_wc(FASTBOOT_DUMP_LOG_ADDR, FASTBOOT_DUMP_LOG_SIZE);
	}
	if (!fastbootlog_buff) {
		printk(KERN_ERR
		       "%s: fail to get the virtual address of fastbootlog\n",
		       __func__);
		return -1;
	}

	head = (struct fastbootlog_head *)fastbootlog_buff;
	check_fastbootlog_head(head, &need_dump_whole);
	if (need_dump_whole) {
		head->lastlog_start = 0;
		head->lastlog_offset = 0;
		head->log_start = 0;
		head->log_offset = FASTBOOT_DUMP_LOG_SIZE;
	}

	lastlog_start = fastbootlog_buff + head->lastlog_start;
	if (head->lastlog_offset < head->lastlog_start) {
		tmp_len = FASTBOOT_DUMP_LOG_SIZE - head->lastlog_start;
		lastlog_size = tmp_len + head->lastlog_offset -
		    sizeof(struct fastbootlog_head);

		s_last_fastbootlog_buff = vmalloc(lastlog_size);
		if (!s_last_fastbootlog_buff) {
			printk(KERN_ERR
			       "%s: fail to vmalloc %#x bytes s_last_fastbootlog_buff\n",
			       __func__, lastlog_size);
			ret = -1;
			goto out;
		}
		memcpy(s_last_fastbootlog_buff, lastlog_start, tmp_len);
		lastlog_start = fastbootlog_buff + sizeof(struct fastbootlog_head);
		memcpy(s_last_fastbootlog_buff + tmp_len, lastlog_start,
		       lastlog_size - tmp_len);
		s_last_fastbootlog_size = lastlog_size;
	} else {
		lastlog_size = head->lastlog_offset - head->lastlog_start;
		if (lastlog_size > 0) {
			s_last_fastbootlog_buff = vmalloc(lastlog_size);
			if (!s_last_fastbootlog_buff) {
				printk(KERN_ERR
				       "%s: fail to vmalloc %#x bytes s_last_fastbootlog_buff\n",
				       __func__, lastlog_size);
				ret = -1;
				goto out;
			}
			memcpy(s_last_fastbootlog_buff, lastlog_start,
			       lastlog_size);
			s_last_fastbootlog_size = lastlog_size;
		}
	}

	log_start = fastbootlog_buff + head->log_start;
	if (head->log_offset < head->log_start) {
		tmp_len = FASTBOOT_DUMP_LOG_SIZE - head->log_start;
		log_size = tmp_len + head->log_offset -
		    sizeof(struct fastbootlog_head);

		s_fastbootlog_buff = vmalloc(log_size);
		if (!s_fastbootlog_buff) {
			printk(KERN_ERR
			       "%s: fail to vmalloc %#x bytes s_fastbootlog_buff\n",
			       __func__, log_size);
			ret = -1;
			goto out;
		}
		memcpy(s_fastbootlog_buff, log_start, tmp_len);
		log_start = fastbootlog_buff + sizeof(struct fastbootlog_head);
		memcpy(s_fastbootlog_buff + tmp_len, log_start,
		       log_size - tmp_len);
		s_fastbootlog_size = log_size;
	} else {
		log_size = head->log_offset - head->log_start;
		if (log_size > 0) {
			s_fastbootlog_buff = vmalloc(log_size);
			if (!s_fastbootlog_buff) {
				printk(KERN_ERR
				       "%s: fail to vmalloc %#x bytes s_fastbootlog_buff\n",
				       __func__, log_size);
				ret = -1;
				goto out;
			}
			memcpy(s_fastbootlog_buff, log_start, log_size);
			s_fastbootlog_size = log_size;
		}
	}

out:
	if (use_ioremap && fastbootlog_buff) {
		iounmap(fastbootlog_buff);
	}

	if (s_last_fastbootlog_buff) {
		bootloader_logger_dump(s_last_fastbootlog_buff,
				       s_last_fastbootlog_size, "last");
		balong_create_log_proc_entry("last_fastboot_log",
					     S_IRUSR | S_IRGRP,
					     &last_fastbootlog_dump_file_fops,
					     NULL);
	}
	if (s_fastbootlog_buff) {
		bootloader_logger_dump(s_fastbootlog_buff, s_fastbootlog_size,
				       "current");
		balong_create_log_proc_entry("fastboot_log", S_IRUSR | S_IRGRP,
					     &fastbootlog_dump_file_fops, NULL);
	}

	return ret;
}