#include <linux/fs.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>

MODULE_LICENSE("GPL");

// TODO: Hier müssen die eigenen IDs eingetragen werden.
#define MY_VENDOR_ID <§§I>0x10b7<§§I>
#define MY_DEVICE_ID <§§I>0x5157<§§I>

static unsigned long ioport=0L, iolen=0L, memstart=0L, memlen=0L;

static irqreturn_t pci_isr( int irq, void *dev_id, struct pt_regs *regs )
{
	return IRQ_HANDLED;
}

static int DeviceInit(struct pci_dev *dev, const struct pci_device_id *id)
{
	printk("0x%4.4x|0x%4.4x: \"%s\"\n", dev->vendor, dev->device,
				dev->dev.name );
	if( request_irq(dev->irq,pci_isr,SA_INTERRUPT|SA_SHIRQ,"pci_drv",NULL) ) {
		printk( KERN_ERR "pci_drv: IRQ %d not free.\n", dev->irq );
		return -EIO;
	}
	ioport = pci_resource_start( dev, 0 );
	iolen = pci_resource_len( dev, 0 );
	if( request_region( ioport, iolen, dev->dev.name )==NULL ) {
		printk(KERN_ERR "I/O address conflict for device \"%s\"\n",
				dev->dev.name);
		goto cleanup_irq;
	}
	memstart = pci_resource_start( dev, 1 );
	memlen = pci_resource_len( dev, 1 );
	if( request_mem_region( memstart, memlen, dev->dev.name )==NULL ) {
		release_region( ioport, iolen );
		printk(KERN_ERR "Memory address conflict for device \"%s\"\n",
				dev->dev.name);
		goto cleanup_ports;
	}
	pci_enable_device( dev );
	return 0;
cleanup_ports:
	release_region( ioport, iolen );
cleanup_irq:
	free_irq( dev->irq, "pci_drv" );
	return -EIO;
}

static void DeviceDeInit( struct pci_dev *pdev )
{
	free_irq( pdev->irq, "pci_drv" );
	if( ioport )
		release_region( ioport, iolen );
	if( memstart )
		release_mem_region( memstart, memlen );
}

static struct file_operations PCIFops;

static struct pci_device_id pci_drv_tbl[] __devinitdata = {
	{ MY_VENDOR_ID, MY_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
	{ 0, }
};

static struct pci_driver pci_drv = {
	.name= "pci_drv",
	.id_table= pci_drv_tbl,
	.probe= DeviceInit,
	.remove= DeviceDeInit,
};

static int __init pci_drv_init(void)
{
	if(register_chrdev(240, "PCI-Driver", &PCIFops)==0) {
		if( pci_module_init(&pci_drv) == 0 )
			return 0;
		unregister_chrdev(240,"PCI-Driver");
	}
	return -EIO;
}

static void __exit pci_drv_exit(void)
{
	pci_unregister_driver( &pci_drv );
	unregister_chrdev(240,"PCI-Driver");
}

module_init(pci_drv_init);
module_exit(pci_drv_exit);
