/** @par LICENCE
* @verbatim
Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.

        ADDI-DATA GmbH
        Dieselstrasse 3
        D-77833 Ottersweier
        Tel: +19(0)7223/9493-0
        Fax: +49(0)7223/9493-92
        http://www.addi-data-com
        info@addi-data.com

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

You shoud also find the complete GPL in the COPYING file
accompanying this source code.

* @endverbatim
*/

/*
  +-----------------------------------------------------------------------+
  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
  +-----------------------------------------------------------------------+
  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
  +-----------------------------------------------------------------------+
  | Project   : API APCI1032      | Compiler : GCC                        |
  | Modulname : APCI1032.C        | Version  : 2.96 (SuSE 7.1 - 2.2.18)   |
  | Version   : 01.00.01          |                                       |
  +-------------------------------+---------------------------------------+
  | Author    : STOLZ, Eric       | Date     : 21.10.2001                 |
  +-----------------------------------------------------------------------+
  |                   Description : APCI1032 main module                  |
  +-----------------------------------------------------------------------+
  |                             UPDATE'S                                  |
  +-----------------------------------------------------------------------+
  |   Date   |   Author  |          Description of updates                |
  +----------+-----------+------------------------------------------------+
  | 29.09.04 | J. Krauth | - Correction from read 1 digital input         |
  |          |           | - Changes in APCI1032_release and fops struct  |
  +-----------------------------------------------------------------------+
*/


#include "apci1032-private.h"
#include <apci1032-kapi.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/sysfs.h>
#endif

//BEGIN JK 06.12.2004: Module informatIon
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>");
MODULE_DESCRIPTION("APCI-1032 IOCTL driver");

EXPORT_SYMBOL(APCI1032_Read1DigitalInput);
EXPORT_SYMBOL(APCI1032_Read8DigitalInputs);
EXPORT_SYMBOL(APCI1032_Read16DigitalInputs);
EXPORT_SYMBOL(APCI1032_Read32DigitalInputs);

EXPORT_NO_SYMBOLS;

#ifndef __devinit
#define __devinit
#define __devexit
#define __devinitdata
#define __devexit_p
#endif

//------------------------------------------------------------------------------

atomic_t apci1032_count = ATOMIC_INIT(0);
unsigned int apci1032_majornumber = 0;

//------------------------------------------------------------------------------
static int __devinit apci1032_probe_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void __devexit apci1032_remove_one(struct pci_dev *dev);

//------------------------------------------------------------------------------
/** The ID table is an array of struct pci_device_id ending with a all-zero entry.
Each entry consists of:

	- vendor, device	Vendor and device ID to match (or PCI_ANY_ID)
	- subvendor,	Subsystem vendor and device ID to match (or PCI_ANY_ID)
	- subdevice class,		Device class to match. The class_mask tells which bits
	- class_mask	of the class are honored during the comparison.
	- driver_data	Data private to the driver.
*/

static struct pci_device_id apci1032_pci_tbl[] __devinitdata = {
	{
		APCI1032_BOARD_VENDOR_ID,
		APCI1032_BOARD_DEVICE_ID,
		PCI_ANY_ID,
		PCI_ANY_ID,
		0,
		0,
		0
	},

	{ 0 },	/* terminate list */
};

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static struct class * apci1032_class = NULL;
#endif

MODULE_DEVICE_TABLE (pci, apci1032_pci_tbl);

//----------------------------------------------------------------------------------------------------------------------
static struct pci_driver apci1032_pci_driver = {
	.name		= __DRIVER_NAME,
	.probe		= apci1032_probe_one,
	.remove		= __devexit_p(apci1032_remove_one),
	.id_table	= apci1032_pci_tbl,
};

//----------------------------------------------------------------------------------------------------------------------


/* Prototypes of the used functions */
int APCI1032_open   (struct inode *inode, struct file *filp);
int APCI1032_release(struct inode *inode, struct file *filp);
int APCI1032_ioctl  (struct        inode *inode,
                     struct        file *filp,
		     unsigned int  cmd,
		     unsigned long arg);



//------------------------------------------------------------------------------
static struct file_operations apci1032_fops = {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
	.ioctl          = apci1032_ioctl_lookup,
#else
	.unlocked_ioctl = apci1032_ioctl_lookup,
#endif
	.open		= apci1032_open_lookup,
	.release	= apci1032_release_lookup,
};

//-------------------------------------------------------------------
/** called when a new card is detected.
 *
 * Historically - in former ADDI-DATA drivers data about a board has been stored
 * in a static structure.
 * This led to huge duplication of information since most of these information
 * are already present in the pci_dev struct.
 *
 * Now the apci1032_str_BoardInformations contains a field "dev", a pointer to
 * the OS PCI device structure.
 *
 *  */
static int __devinit apci1032_probe_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
      {
    	int ret = pci_enable_device(dev);
        if (ret)
        {
        	printk(KERN_ERR "%s: pci_enable_device failed\n",__DRIVER_NAME);
		return ret;
	}
      }

	/* 2.4 only : check_region is deprecated in 2.6 */
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		/* check if BAR 0 is free */
		if ( check_region(dev->resource[0].start, 4) )
		{
			printk(KERN_WARNING "%s: BAR 0 (%lX) is already in use\n",__DRIVER_NAME,dev->resource[0].start);
			return -EBUSY;
		}
		/* check if BAR 1 is free */
		if ( check_region(dev->resource[1].start, 32) )
		{
			printk(KERN_WARNING "%s: BAR 1 (%lX) is already in use\n",__DRIVER_NAME,dev->resource[1].start);
			return -EBUSY;
		}
	#endif // 2.4

	/* allocate a new data structure containing board private data */
	{
		struct apci1032_str_BoardInformations * newboard_data = NULL;
		newboard_data = kmalloc( sizeof( struct apci1032_str_BoardInformations) , GFP_ATOMIC);
		if (!newboard_data)
		{
			printk(KERN_CRIT "Can't allocate memory for new board %s\n",pci_name(dev));
			return -ENOMEM;
		}
		/* link standard data structure to the board's private one */
		pci_set_drvdata(dev,newboard_data);

		apci1032_init_priv_data(newboard_data);
	}

	/* allocate BAR 0 to 2 memory regions */
    {
    	int ret = pci_request_regions(dev,__DRIVER_NAME);
        if (ret)
        {
        	printk(KERN_ERR "%s: pci_request_regions failed\n",__DRIVER_NAME);
		/* free all allocated ressources here*/
		return ret;
	}
      }

	{
		/* increase the global board count */
		atomic_inc(&apci1032_count);
		printk(KERN_INFO "%s: board %s managed (minor number will be %d) \n",__DRIVER_NAME, pci_name(dev), atomic_read(&apci1032_count)-1);
	}

	/* create */
	apci1032_proc_create_device(dev, atomic_read(&apci1032_count)-1);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
	while(1)
	{
		#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
			struct class_device *cdev;
		#else
			struct device *cdev;
		#endif

			int minor = (atomic_read(&apci1032_count)-1);

			/* don't execute if class not exists */
			if (IS_ERR(apci1032_class))
					break;

		#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
			cdev = class_device_create (apci1032_class, NULL, MKDEV(apci1032_majornumber, minor), NULL, "%s_%d", __DRIVER_NAME, minor);
		#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
			cdev = device_create (apci1032_class, NULL, MKDEV(apci1032_majornumber, minor), "%s_%d", __DRIVER_NAME, minor);
		#else
			cdev = device_create (apci1032_class, NULL, MKDEV(apci1032_majornumber, minor), NULL, "%s_%d", __DRIVER_NAME, minor);
		#endif

			if (IS_ERR(cdev))
			{
					printk (KERN_WARNING "%s: class_device_create error\n", __DRIVER_NAME);
			}
			break;
	}
#endif

	return 0;
}


//------------------------------------------------------------------------------
/** This function registers the driver with register_chrdev.
 *
 * @todo For kernel 2.6, use udev
 *  */

static int apci1032_register(void)
{

	//Registration of driver
	apci1032_majornumber = register_chrdev(0, __DRIVER_NAME, &apci1032_fops);

	if (apci1032_majornumber < 0)
	{
		printk (KERN_ERR "%s: register_chrdev returned %d ... aborting\n",__DRIVER_NAME,apci1032_majornumber);
		return -ENODEV;
	}
	return 0;
}

//------------------------------------------------------------------------------
/** Called when module loads. */
static int __init apci1032_init(void)
{

	/* 2.4 only : check_region is deprecated in 2.6 */
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		/* Detection if an PCI Bus is present */
		if(!pci_present())
		{
			printk(KERN_WARNING "%s: NO PCI BUS.\n", __DRIVER_NAME);
			return -ENODEV;
		}
	#endif

	if( apci1032_register() )
	{
		return -ENODEV;
	}


#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
        apci1032_class = ADDI_CLASS_CREATE(THIS_MODULE, __DRIVER_NAME);
        if (IS_ERR(apci1032_class))
        {
                printk (KERN_WARNING "%s: class_create error\n",__DRIVER_NAME );

        }
#endif

	/* registred, now create root /proc entry */
	apci1032_proc_init();

	printk(KERN_INFO "%s: loaded\n",__DRIVER_NAME);

	/* now, subscribe to PCI bus subsystem  */
	/** @note The module will load anyway even if the call to pci_module_init() fails */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
	if ( pci_module_init (&apci1032_pci_driver) != 0)
#else
	if ( pci_register_driver (&apci1032_pci_driver) != 0)
#endif
	{
		printk("%s: no device found\n",__DRIVER_NAME);
		apci1032_pci_driver.name = "";
	}



	return 0;
}

//-------------------------------------------------------------------
/** a card is removed */
static void __devexit apci1032_remove_one(struct pci_dev *dev)
{

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
        while(1)
        {
			int minor = (atomic_read(&apci1032_count)-1);

			/* don't execute if class not exists */
			if(IS_ERR(apci1032_class))
					break;

			#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
				class_device_destroy (apci1032_class, MKDEV(apci1032_majornumber, minor));
			#else
				device_destroy (apci1032_class, MKDEV(apci1032_majornumber, minor));
			#endif

            break;
        }
#endif

	pci_disable_device(dev);

	/* deallocate BAR 0 to 2 memory regions */
	pci_release_regions(dev);

	/* free private device data*/
	if (APCI1032_PRIVDATA(dev))
		kfree(APCI1032_PRIVDATA(dev));

	apci1032_proc_release_device(dev);

	atomic_dec(&apci1032_count);

	printk("%s: board %s unloaded \n",__DRIVER_NAME,pci_name(dev));

}

//------------------------------------------------------------------------------
/** This function unregisters the driver with unregister_chrdev.
 *
 * @todo For kernel 2.6, use udev
 *  */

static void apci1032_unregister(void)
{
	unregister_chrdev(apci1032_majornumber, __DRIVER_NAME);
}

//-------------------------------------------------------------------
/** Called when module is unloaded. */
static void __exit apci1032_exit(void)
{

	/* Cleans the module from the kernel */
	if (apci1032_pci_driver.name[0])
	{
		pci_unregister_driver (&apci1032_pci_driver);
	}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
        /* don't execute if class not exists */
        if ( !IS_ERR(apci1032_class) )
                class_destroy (apci1032_class);
#endif

	apci1032_unregister();
	apci1032_proc_release();
}
//------------------------------------------------------------------------------
module_exit(apci1032_exit);
module_init(apci1032_init);
