#include "driver.h"
#include <linux/types.h>
#include <stdio.h>
#include <string.h>
#include "com_gpio.h"
#include "hal_interface_api.h"
#include "linux/fcntl.h"

#define DEV_NAME	"/dev/fmc_cpld"


int fmc_write_8bit(uint32_t address, uint8_t *buf, uint32_t len)
{
	int fd;
	fmc_cpld_t fmc_arg;
	uint32_t remLen = len, writeCnt = 0;;
	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}

	
	while(remLen > 1024)
	{
		fmc_arg.address = address + writeCnt;
		fmc_arg.length = 1024;
		memcpy(fmc_arg.data, buf+writeCnt, 1024);
		ioctl(fd, WRITE_BYTE, &fmc_arg);		
		writeCnt += 1024;
		remLen -= 1024;
	}

	if(remLen > 0)
	{
		fmc_arg.address = address + writeCnt;
		fmc_arg.length = remLen;
		memcpy(fmc_arg.data, buf+writeCnt, remLen);
		ioctl(fd, WRITE_BYTE, &fmc_arg);	
		writeCnt += remLen;
		remLen = 0;
	}

	close(fd);
	return 0;
}

int fmc_read_8bit(uint32_t address, uint8_t *buf, uint32_t len)
{
	int fd;
	fmc_cpld_t fmc_arg;
	uint32_t remLen = len, readCnt = 0;

	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}

	while(remLen > 1024)
	{
		fmc_arg.address = address + readCnt;
		fmc_arg.length = 1024;
		ioctl(fd, READ_BYTE, &fmc_arg);		
		memcpy(buf+readCnt, fmc_arg.data, 1024);
		readCnt += 1024;
		remLen -= 1024;
	}

	if(remLen > 0)
	{
		fmc_arg.address = address + readCnt;
		fmc_arg.length = remLen;
		ioctl(fd, READ_BYTE, &fmc_arg);	
		memcpy( buf+readCnt, fmc_arg.data, remLen);
		readCnt += remLen;
		remLen = 0;
	}
	close(fd);
	return 0;
}


int fmc_write_16bit(uint32_t address, uint16_t *buf, uint32_t len)
{
	int fd;
	fmc_cpld_t fmc_arg;
	uint32_t remLen = len*sizeof(uint16_t), writeCnt = 0;;
	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}
	
	while(remLen > 1024)
	{
		fmc_arg.address = address + writeCnt;
		fmc_arg.length = 1024/sizeof(uint16_t);
		memcpy(fmc_arg.data, buf+writeCnt, 1024);
		ioctl(fd, WRITE_SHORT, &fmc_arg);		
		writeCnt += 1024;
		remLen -= 1024;
	}

	if(remLen > 0)
	{
		fmc_arg.address = address + writeCnt;
		fmc_arg.length = remLen/sizeof(uint16_t);
		memcpy(fmc_arg.data, buf+writeCnt, remLen);
		ioctl(fd, WRITE_SHORT, &fmc_arg);	
		writeCnt += remLen;
		remLen = 0;
	}

	close(fd);
	return 0;
}

int fmc_read_16bit(uint32_t address, uint16_t *buf, uint32_t len)
{
	int fd;
	fmc_cpld_t fmc_arg;
	uint32_t remLen = len*sizeof(uint16_t), readCnt = 0;

	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}

	while(remLen > 1024)
	{
		fmc_arg.address = address + readCnt;
		fmc_arg.length = 1024/sizeof(uint16_t);
		ioctl(fd, READ_SHORT, &fmc_arg);		
		memcpy(buf+readCnt, fmc_arg.data, 1024);
		readCnt += 1024;
		remLen -= 1024;
	}

	if(remLen > 0)
	{
		fmc_arg.address = address + readCnt;
		fmc_arg.length = remLen/sizeof(uint16_t);
		ioctl(fd, READ_SHORT, &fmc_arg);	
		memcpy( buf+readCnt, fmc_arg.data, remLen);
		readCnt += remLen;
		remLen = 0;
	}
	close(fd);
	return 0;
}


int fmc_write_32bit(uint32_t address, uint32_t *buf, uint32_t len)
{
	int fd;
	fmc_cpld_t fmc_arg;
	uint32_t remLen = len*sizeof(uint32_t), writeCnt = 0;;
	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}
	
	while(remLen > 1024)
	{
		fmc_arg.address = address + writeCnt;
		fmc_arg.length = 1024/sizeof(uint32_t);
		memcpy(fmc_arg.data, buf+writeCnt, 1024);
		ioctl(fd, WRITE_WORD, &fmc_arg);		
		writeCnt += 1024;
		remLen -= 1024;
	}

	if(remLen > 0)
	{
		fmc_arg.address = address + writeCnt;
		fmc_arg.length = remLen/sizeof(uint32_t);
		memcpy(fmc_arg.data, buf+writeCnt, remLen);
		ioctl(fd, WRITE_WORD, &fmc_arg);	
		writeCnt += remLen;
		remLen = 0;
	}

	close(fd);
	return 0;
}

int fmc_read_32bit(uint32_t address, uint32_t *buf, uint32_t len)
{
	int fd;
	fmc_cpld_t fmc_arg;
	uint32_t remLen = len*sizeof(uint32_t), readCnt = 0;

	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}

	while(remLen > 1024)
	{
		fmc_arg.address = address + readCnt;
		fmc_arg.length = 1024/sizeof(uint32_t);
		ioctl(fd, READ_WORD, &fmc_arg);		
		memcpy(buf+readCnt, fmc_arg.data, 1024);
		readCnt += 1024;
		remLen -= 1024;
	}

	if(remLen > 0)
	{
		fmc_arg.address = address + readCnt;
		fmc_arg.length = remLen/sizeof(uint32_t);
		ioctl(fd, READ_WORD, &fmc_arg);	
		memcpy( buf+readCnt, fmc_arg.data, remLen);
		readCnt += remLen;
		remLen = 0;
	}
	close(fd);
	return 0;
}


int fmc_set_bus_width(uint8_t bus_is16bit)
{
	int fd;
	
	fd = open(DEV_NAME, O_RDWR);
	if(-1 == fd)
	{
		printf("Open %s failed!\n", DEV_NAME);
		return -1;
	}

	if(bus_is16bit)
		ioctl(fd, BUS_16BIT, NULL);			
	else
		ioctl(fd, BUS_8BIT, NULL);			

	close(fd);
	return 0;
}

