#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>

#define FORT_MINOR 254
#define VERSION "0.1alpha1 (C)2002 Robert Swiecki"

#define QUANT 4

MODULE_AUTHOR("Robert Swiecki <rswieck1@elka.pw.edu.pl>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Fortunator device");

char *fort_table[] = {
	
	"Taki tam tekst",
	"Ten też idiotyczny",
	"Po co Ty to czytasz?",
	"IdĽ się czym¶ zajmij",

	NULL
};

// static struct which indicates status of the device
static struct fstatus {
	int inuse;
	int item;
	int size;
} fortstatus;

// open and initialize variables
int
fort_open(struct inode *i, struct file *f)
{
	int x;

	if (fortstatus.inuse) {
		printk(KERN_INFO "Sorry: Fortunator currently in use\n");
		return -EBUSY;
	}

	/* Should be random thing */
	fortstatus.item = jiffies % QUANT;

	/* Evaluate size */
	fortstatus.size = -1;
	while (fort_table[fortstatus.item][(fortstatus.size++) + 1]) ;

	return 0;
}

// close device, clear 'inuse' var
int
fort_release(struct inode *i, struct file *f)
{
	fortstatus.inuse = 0;

	return 0;
}

// read function
ssize_t
fort_read(struct file * f, char *buf, size_t count, loff_t * ppos)
{
	size_t x = *ppos;

	/* Nothing to return */
	if (count == 0)
		return 0;

	/* Too far */
	if (*ppos > fortstatus.size)
		return 0;

	/* Read until end and no more than 'count' bytes */
	while ((*ppos <= fortstatus.size) && ((*ppos - x) <= count))
		buf[*ppos - x] = fort_table[fortstatus.item][(*ppos)++];

	/* How many we've returned */
	return *ppos - x;
}

// available operations
struct file_operations fort_fops = {
	read:fort_read,
	open:fort_open,
	release:fort_release
};

// struct used to bind module to the device of 10,FORT_MINOR
static struct miscdevice fort_dev = {
	FORT_MINOR, "fort", &fort_fops
};

// Init module, display usefull information
int
init_module(void)
{
	int stat;

	if ((stat = misc_register(&fort_dev))) {
		printk(KERN_INFO "Fortunator: error registering misc_device\n");
		return stat;
	}
	
	printk(KERN_INFO "Fortunator %s: registered fort device\n", VERSION);

	fortstatus.inuse = 0;

	return 0;
}

// Remove module
void
cleanup_module(void)
{
	printk(KERN_INFO "Fortunator: deregistering fort device\n");
	misc_deregister(&fort_dev);
}
