#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>

#define RAMDISK_ADDR 0x00a00000

#define DMA_BASE 0xd1200000
#define DMA_SRC	0
#define DMA_DST 1
#define DMA_LEN 2
#define DMA_RESET 3
#define DMA_IRQ_DISABLED 4

#define USE_DMA 0

FS_DEF(ram);
struct fs_ops file_system[] = {
	{ram_open, ram_close, ram_read, ram_write, ram_seek, ram_stat},
};
int nfsys=1;

int
ram_open( const char *path, struct open_file *f)
{
	printf("ram_open\n");
	f->f_fsdata=(void *)(vaddr_t)RAMDISK_ADDR;
	return 0;
}

int
ram_read( struct open_file *f, void *addr, size_t size,  size_t *resid)
{
	char *srcaddr = (void *)f->f_fsdata;
	printf("ram_read %p %d", addr, size);
#if USE_DMA
	{
		size_t dmasize = size & ~0x3;
		printf(" DMA src 0x%x 0x%x", *(int *)srcaddr, *(int *)(srcaddr+dmasize - 4));
		volatile uint32_t *dmareg = (void*)DMA_BASE;
		dmareg[DMA_DST] = (vaddr_t)addr;
		dmareg[DMA_SRC] = (vaddr_t)srcaddr;
		dmareg[DMA_LEN] = dmasize;
		while (dmareg[DMA_LEN] != 0)
			;
		dmareg[DMA_RESET] = 0;
		printf(" dst 0x%x 0x%x", *((int *)addr), *((int *)((char *)addr+dmasize - 4)));
		srcaddr = (void *)((paddr_t)srcaddr + size);
		addr = (void *)((paddr_t)addr + size);
		size -= dmasize;
		if (size) {
			printf(" memcpy(%p, %p, %d)", srcaddr, addr, size);
			memcpy(addr, srcaddr, size);
		}
	}
#else /* USE_DMA */
	printf(" memcpy(%p, %p, %d)", addr, srcaddr, size);
	memcpy(addr, srcaddr, size);
#endif

	if (resid)
		*resid = 0;
	srcaddr += size;
	f->f_fsdata = srcaddr;
	printf(" done\n");
	return(0);
}

int
ram_close(struct open_file *f)
{
	printf("ram_close\n");
	return(0);
}


int
ram_write(struct open_file *f, void *start, size_t size, size_t *resid)
{
	return (EROFS);
}

int
ram_stat( struct open_file *f, struct stat *sb)
{
	printf("ram_stat\n");
	sb->st_mode = 0444;
	sb->st_nlink = 1;
	sb->st_uid = 0;
	sb->st_gid = 0;
	sb->st_size = -1;
	return (0);
}

off_t
ram_seek(struct open_file *f, off_t offset, int where)
{
	char *srcaddr = (void *)f->f_fsdata;

	printf("ram_seek %d %d\n", (int)offset, where);
	switch (where) {
	case SEEK_SET:
		srcaddr=(void *)((vaddr_t)RAMDISK_ADDR + (vaddr_t)offset);
		break;
	case SEEK_CUR:
		srcaddr += offset;
		break;
	case SEEK_END:
	default:
		errno = EOFFSET;
		return -1;
	}
	f->f_fsdata = srcaddr;
	return ((vaddr_t)srcaddr - (vaddr_t)RAMDISK_ADDR);
}

int
devopen( struct open_file *f, const char *fname, char **file)
{
	printf("devopen\n");
	f->f_flags |= F_NODEV;
	*file = "netbsd";
	return 0;
}

