/*
 * This teaching version modified by Corey Manders September 2004
 *
 * Revision 1.2: By Yacine (yacine@eyetap.org) Summer 2001
 *              * The driver now compiles under the Linux kernel 2.4.X
 *
 * Revision 1.1: By Taneem (taneem@eyetap.org) Tue Sep  5 20:36:44 EDT 2000
 *    	      	* Fixed the bug so that there won't be a mix up in minor numbers.
 *    	      	* Changed the code so the ibus port number can be changed through
 *                insmod.
 *    	      	       e.g.   insmod module_base=0x278 ibus.o
 *    	      	* Took out the delay while writing (but the code is still there).
 *    	      	* Added some error checking
 *    	      	* Organized the code a bit
 *
 * i-bus2.x.c -- modified simple device driver for compatibility to 2.0 or 2.2
 * original implementation (Erlich, Mann, Fung, etc.) written for 2.0 kernels
 * 2000Apr20 Modified by Behr Raz (g7behr@cdf.utoronto.ca ) to compile under
 * pre and post 2.2.0 KERNEL versions
 *
 * i-bus2.x.c is source code for 2.x (e.g. 2.0 or 2.2 kernels)
 * ibus.o is the object
 * /dev/ibus0 and dev/ibus1 are the devices loaded by  load_i-bus.sh
 * echo -n -e "\377" > /dev/ibus0
 * is non inverting (turns all on)
 * echo -n -e "\377" > /dev/ibus1
 * is inverting (turns all off)
 */

#include <linux/module.h>
#include <linux/param.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>     
#include <linux/errno.h>  
#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/uaccess.h>  
#include <linux/poll.h>
#define   DEFAULT_PARPORT_BASE         0x378
MODULE_LICENSE("GPL");

static int module_major = 0;
static int module_base  = 0;  /* Check module_init */
enum module_modes {I_BUS_DEFAULT=0, I_BUS_INVERT};


/* 
   the file_operations struct contains pointers to
   the local function necessary for file tasks.
 */
struct file_operations module_fops = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
		NULL,
#endif
		NULL,          
		module_read,
		module_write,
		NULL,          
		NULL,       	 
		NULL,          
		NULL,          
		module_open,
		NULL,   
		module_release
	};

MODULE_PARM(module_base, "i");


static int module_open(struct inode *inode, struct file *filp){
	int minor = (MINOR(inode->i_rdev));

	if (minor > 1 && minor < 0) {
		printk("Error IBus: The minor number should be either 0 or 1\n");
		return -EINVAL;
	}
	MOD_INC_USE_COUNT;
	return 0;
}

static int module_release(struct inode *inode, struct file *filp){ 

	MOD_DEC_USE_COUNT;
	return 0;
}

static ssize_t module_read(
		struct file *filp,
		char *buf,        
		size_t count,     
		loff_t *offset){  

}

static ssize_t module_write(
		struct file *filp,
		const char *buf,
		size_t count,
		loff_t *offset
		){


}

int init_module(void){

	int result;

	if (!module_base)    	        /* Check if module_base was set through insmod */
		module_base = DEFAULT_PARPORT_BASE;  /* otherwise set it to DEFAULT_IBUS_BASE */

	result = check_region(module_base,32);
	if (result){
		printk("i-bus2.x: can't get I/O address 0x%x\n",module_base);
		return result;
	}
	request_region(module_base,32,"ibus");

	result = register_chrdev(module_major, "ibus", &module_fops);
	if (result < 0){
		printk("i-bus2.x: can't get major number\n");
		release_region(module_base,32);
		return result;
	}
	if (module_major == 0) module_major = result; /* dynamic */ 

	return 0;
}

void cleanup_module(void){

	unregister_chrdev(module_major, "ibus");
	release_region(module_base,32);
}

