/********************************************************************
 * FILE: 	PCIO	
 * Author: 	Kenny Huang
 *
 * Note: The compiler has to be changed to the Kernal compiler.  Do the following if you make andy changes
 *
 * cd /usr/bin
 * rm cc
 * ln -s kgcc cc
 * cd /home/remora/source/c++/digital_interface
 * make clean
 * make
 * mknod /dev/PCIO c 124 0
 * insmod -f PCIO.o
 * cd /usr/bin
 * rm cc
 * ln-s g++ cc
 * ls -l cc    To check and make sure it points back to g++
 ********************************************************************/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/pci.h> 
#include <linux/string.h>

int minor = 0;
int major = 124;

struct pci_dev *dev = NULL;
unsigned int vendor = 0x494F; 
unsigned int device = 0x0C70;
unsigned int baseaddress = 0;
static char str_baseaddress[32];

/************************ PCIO_open *************************************/

static int PCIO_open(struct inode *inode, struct file *filp)
{
	printk("opening PCIO device driver...\n");


	if (filp->f_mode & FMODE_READ) {
  		//printk("io port, ready for reading...");
	}

	/* increment usage count */
	MOD_INC_USE_COUNT;


	major = MAJOR(inode->i_rdev);
	minor = MINOR(inode->i_rdev);
	printk("major: %d   minor: %d\n", major, minor);

	return 0; 
}



static int PCIO_release(struct inode *inode, struct file *filp)
{
	MOD_DEC_USE_COUNT;
	printk("PCIO device driver closed\n");
	return 0;

}


/************************ PCIO_read *************************************/


static ssize_t PCIO_read(struct file *filp, char *buf,
			   size_t channel, loff_t *offp)
{	
	return (ssize_t) baseaddress;
}



/************************* file operations ********************************/

struct file_operations PCIO_fops = {
	NULL,		
	PCIO_read, 	//IO16_read,		
	NULL,		// don't need write for our case	
	NULL,			
	NULL,	
	NULL,
	NULL,
	PCIO_open,
	NULL,
	PCIO_release
};


/**************************** init_module *************************************/

int init_module(void)
{
  	int err;
	/* 
         * register the device with the kernel 
	 * NOTE: 60-63, 240-254 are experimental range 
	 * 	 our device is registered with 125 and 0
	 */
	if ((err = register_chrdev(major, "PCIO", &PCIO_fops)) < 0 )
        	printk("unable to register device\n");
	//printk("registered device: %d successfully\n", err);

	if (!pci_present())
		return -ENODEV;

	dev = pci_find_device(vendor, device, dev);
	if (!dev) {
		printk("dev is NULL\n");
		return -1;
	}
	else {
		//printk("vendor: %X\n", dev->vendor);
		//printk("device: %X\n", dev->device);
		printk("BASEADDRESS[2]: %X\n", dev->base_address[2] - 1);
		baseaddress = dev->base_address[2] - 1;
		printk("baseaddress: %X\n", baseaddress);
	}
	
	return 0;
}


/**************************** ges_cleanup *************************************/

void cleanup_module(void)
{
	unregister_chrdev(major, "PCIO");
	MOD_DEC_USE_COUNT;
   	printk("goodbye\n");
}








