
/**
@file shell_memory.c
*/
/********************************************************************************************
Debug Switch Definition Section
********************************************************************************************/


/********************************************************************************************
Include File Section
********************************************************************************************/
#include "shell_inode.h"
#include "shell_file.h"
#include "string.h"
/********************************************************************************************
Macro Definition Section
********************************************************************************************/
typedef enum
{
	MEM_ACESS_ERR = 0,
	MEM_READ_ONLY,
	MEM_READ_WRITE,
} PERMISSON;

typedef struct
{
	uint32_t start_addr;
	uint32_t end_addr;
	PERMISSON  permit;
} MEMORY_REGION;

enum
{
	REGION_FLASH = 0,
	REGION_RAM,
	REGION_IO,
	REGION_MAX,
};

/* ----------------------------[private macro]-------------------------------*/
#define MEMORY_NAME			"memory"
#define MEMORY_USER_MODE		(0)
#define MEMORY_ROOT_MODE		( F_READ_MASK | F_WRITE_MASK)

#define SRAM_START_ADDR		(0x40000000)
#define SRAM_END_ADDR		(0x400BFFFF)
#define SINGLE_READ_SIZE	(16)
#define SINGLE_WRITE_SIZE	(16)

#define FLASH_START_ADDR	(0x0F90000)
#define FLASH_END_ADDR		(0x0157FFFF)

#define IO_MEM_START		(0xF0000000)
#define IO_MEM_END			(0xFFFFFFFF)

/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
#if 0
static int32_t memory_open(struct inode * i_node, struct file * fp,uint8_t counter);
static int32_t memory_ioctl(struct file * fp, uint32_t pdata, unsigned long arg);
static uint32_t memory_read(struct file *fp, uint8_t  *pbuf, uint32_t size, uint32_t *lofft,uint8_t counter);
static uint32_t memory_write(struct file *fp, const uint8_t  *pbuf, uint32_t size, uint32_t *lofft);
static uint32_t memory_llseek(struct file *fp, uint32_t lofft, SHELL_SEEK_WHENCE whence);
static void memory_close(struct file *fp,uint8_t counter);
#endif
/********************************************************************************************
Const Global Variable Definition Section
********************************************************************************************/


/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/
#if 0
static const MEMORY_REGION Mpc5748g_mem[] =
{
	{
		.start_addr = FLASH_START_ADDR,
		.end_addr = FLASH_END_ADDR,
		.permit = MEM_READ_ONLY,
	},
	{
		.start_addr = 	SRAM_START_ADDR,
		.end_addr = SRAM_END_ADDR,
		.permit = MEM_READ_WRITE,
	},
	{
		.start_addr = 	IO_MEM_START,
		.end_addr = IO_MEM_END,
		.permit = MEM_READ_WRITE,
	}
};
#endif
/* ----------------------------[private variables]---------------------------*/
#if 0
static struct file_operations memory_ops=\
{
	.open = memory_open,
	.close = memory_close,
	.read = memory_read,
	.write = memory_write,
	.ioctl = memory_ioctl,
	.llseek = memory_llseek,
};
#endif
#if 0
static NODE_MODE memory_mode = \
{
	.i_mode_root = MEMORY_ROOT_MODE,
	.i_mode_user = MEMORY_USER_MODE,
};
#endif
//static uint32_t addr_offset = 0;
//static uint8_t CurRegion = REGION_FLASH;
/********************************************************************************************
Function Definition Section
********************************************************************************************/
#if 0
/**
 * Convert address to strange block format that freescale likes.
 *
 * @param addr
 * @param size
 * @param fb
 * @return
 */
static int32_t memory_open(struct inode * i_node, struct file * fp,uint8_t counter)
{
	return 0;
}

static int32_t memory_ioctl(struct file * fp, uint32_t pdata, unsigned long arg)
{
	return 0;
}

static uint32_t memory_read(struct file *fp, uint8_t  *pbuf, uint32_t size, uint32_t *lofft,uint8_t counter)
{
	uint32_t read_size = 0;

	if(Mpc5748g_mem[CurRegion].permit < MEM_READ_ONLY)
	{
		return read_size;
	}

	if((addr_offset >= Mpc5748g_mem[CurRegion].start_addr) && (addr_offset < Mpc5748g_mem[CurRegion].end_addr))
	{
		read_size = SINGLE_READ_SIZE > size ? size : SINGLE_READ_SIZE;

		if(addr_offset + read_size > Mpc5748g_mem[CurRegion].end_addr)
		{
			read_size = Mpc5748g_mem[CurRegion].end_addr - addr_offset;
		}

		if(REGION_IO != CurRegion)
		{
			memcpy(pbuf, (uint8_t *)(addr_offset), read_size);
		}
		else
		{
			/*align check*/
			if((0 != addr_offset % 4) && (size % 4))
			{
				read_size = 0;
			}
			else
			{
				int32_t i = 0;
				uint32_t *databuf = (uint32_t *)pbuf;
				for(i = 0; i < (size / 4); i++)
				{
					*databuf = *(uint32_t *)addr_offset;
					databuf++;
					addr_offset += 4;
				}
			}
		}

		addr_offset += read_size;
	}
	else
	{
		;
	}

	return read_size;
}

static uint32_t memory_write(struct file *fp, const uint8_t  *pbuf, uint32_t size, uint32_t *lofft)
{
	uint32_t write_size = 0;

	if(Mpc5748g_mem[CurRegion].permit < MEM_READ_WRITE)
	{
		return write_size;
	}

	if((addr_offset >= Mpc5748g_mem[CurRegion].start_addr) && (addr_offset < Mpc5748g_mem[CurRegion].end_addr))
	{
		write_size = SINGLE_READ_SIZE > size ? size : SINGLE_READ_SIZE;

		if(addr_offset + write_size > Mpc5748g_mem[CurRegion].end_addr)
		{
			write_size = Mpc5748g_mem[CurRegion].end_addr - addr_offset;
		}

		if(REGION_IO != CurRegion)
		{
			memcpy((uint8_t *)(addr_offset), pbuf, write_size);
		}
		else
		{
			/*align check*/
			if((0 != addr_offset % 4) && (size % 4))
			{
				write_size = 0;
			}
			else
			{
				int32_t i = 0;
				uint32_t *databuf = (uint32_t *)pbuf;
				for(i = 0; i < (size / 4); i++)
				{
					*(uint32_t *)addr_offset = *databuf;
					databuf++;
					addr_offset += 4;
				}
			}
		}

		addr_offset += write_size;
	}
	else
	{
		;
	}

	return write_size;
}

static uint32_t memory_llseek(struct file *fp, uint32_t lofft, SHELL_SEEK_WHENCE whence)
{
	uint32_t ret = 0;
	int32_t index = 0;

	if(SHELL_SEEK_SET != whence)
	{
		return ret;
	}

	/*find region need to be write*/
	for(index = 0; index < REGION_MAX; index++)
	{
		if((Mpc5748g_mem[index].start_addr <= lofft)&&(Mpc5748g_mem[index].end_addr > lofft))
		{
			addr_offset = lofft;
			CurRegion = index;
			break;
		}
	}

	return lofft;
}

static void memory_close(struct file *fp,uint8_t counter)
{
	return;
}

int32_t memory_inode_init(void)
{
	INODE_STATUS ret = INODE_SUCESS;

	ret = xShellInodeCreate((uint8_t *)MEMORY_NAME, &memory_mode, &memory_ops);

	if(INODE_SUCESS == ret)
	{

		return 0;
	}
	else
	{
		return -1;
	}
}

//INODE_INIT(memory_inode_init)
#endif
