#include <sdevice.h>
#include <llist.h>
#include <error.h>
#include <request.h>
#include <console.h>
#include <malloc.h>
#include <fs/vfs.h>
#include <fs/devfs.h>
#include <init.h>
#include <i386/virtual.h>

struct RamDisk
{
	char* data;
	struct StorageDevice* sDev;
};

/* Useful defines */

#define MAX_RAMDISKS 2
#define RAMDISK_SIZE (4*1024*1024) /* In bytes */
#define RAMDISK_SSIZE 1024 /* Sector size, in bytes */

static struct RamDisk disks[MAX_RAMDISKS];
struct StorageDevice rdDevices[MAX_RAMDISKS];

/***********************************************************************
 *
 * FUNCTION:	RamDiskRequest
 *
 * DESCRIPTION: Service a read or write request to a ramdisk.
 *
 * PARAMETERS: data - pointer to a RamDisk structure.
 *
 * RETURNS: 0 if successful, -EIO if request could not be serviced.
 *
 ***********************************************************************/

int RamDiskRequest(void* data)
{
	struct RamDisk* disk=(struct RamDisk*)data;
	struct StorageDevice* sDev=disk->sDev;
	struct Request* request=StorageGetCurrRequest(sDev);
	int reqSize=request->numSectors*RAMDISK_SSIZE;
	int memOffset=request->sector*RAMDISK_SSIZE;
	if (!request)
		return 0;

	if (!disk->data)
	{
		/* Allocate from the malloc range - maybe should choose somewhere else? */
		disk->data=(char*)VirtMapPhysRange(0xC0000000,0xD0000000,RAMDISK_SIZE >> PAGE_SHIFT,3);

		if (!disk->data)
		{
			StorageEndRequest(sDev,ENOMEM);
			return -ENOMEM;
		}
	}

	/* Past the end of the ramdisk? */
	if (memOffset >= (RAMDISK_SIZE-reqSize))
	{
		StorageEndRequest(sDev,EIO);
		return -EIO;
	}

	if (request->type == REQUEST_WRITE)
		memcpy((char*)(disk->data+memOffset),(char*)request->data,reqSize);
	else if (request->type == REQUEST_READ)
		memcpy((char*)request->data,(char*)(disk->data+memOffset),reqSize);

	StorageEndRequest(sDev,0);
	return 0;
}

int RamDiskInit()
{
	int i;

	for (i=0; i<MAX_RAMDISKS; i++)
	{
		char buf[32];

		sprintf(buf,"Storage/RamDisk%d",i);
		disks[i].sDev=&rdDevices[i];
		disks[i].data=NULL;

		/* Set up the storage device structure */
		rdDevices[i].request=RamDiskRequest;
		rdDevices[i].blockSize=RAMDISK_SSIZE;
		rdDevices[i].priv=&disks[i];
		rdDevices[i].totalSectors=RAMDISK_SIZE/RAMDISK_SSIZE;

		DevAddDevice(buf,7,i,DEVICE_BLOCK,&rdDevices[i]);
		StorageAddDevice(&rdDevices[i]);
		StorageQueueInit(&rdDevices[i]);
	}

	KePrint("%d ramdisks loaded, of size %d\n",MAX_RAMDISKS,RAMDISK_SIZE);

	return 0;
}

DeviceInit(RamDiskInit);
