/** @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
*/
#include "apci1032-private.h"
#include <apci1032-kapi.h>

EXPORT_NO_SYMBOLS;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
#define __user 
#endif

//------------------------------------------------------------------------------
int apci1032_do_ioctl(struct pci_dev * pdev, unsigned int cmd, unsigned long arg)
{

    switch(cmd)
    {    
    	
		case CMD_APCI1032_CheckAndGetPCISlotNumber: 
			return do_CMD_APCI1032_CheckAndGetPCISlotNumber(pdev,cmd,arg);
			break;

		case CMD_APCI1032_SetBoardInformation:
			return do_CMD_APCI1032_SetBoardInformation(pdev,cmd,arg);
			break;
       
		case CMD_APCI1032_GetHardwareInformation:
			return do_CMD_APCI1032_GetHardwareInformation(pdev,cmd,arg);
            break; 

		case CMD_APCI1032_Read1DigitalInput:
			return do_CMD_APCI1032_Read1DigitalInput(pdev, cmd, arg);
		    break;

		case CMD_APCI1032_Read8DigitalInput:
			return do_CMD_APCI1032_Read8DigitalInput(pdev, cmd, arg);
			break;

       	case CMD_APCI1032_Read16DigitalInput:
       		return do_CMD_APCI1032_Read16DigitalInput(pdev, cmd, arg);
			break;

		case CMD_APCI1032_Read32DigitalInput:
			return do_CMD_APCI1032_Read32DigitalInput(pdev, cmd, arg);
			break;	    
		
		default:
			return -EINVAL;
			break;
    }
	
}
//------------------------------------------------------------------------------
int do_CMD_APCI1032_CheckAndGetPCISlotNumber(struct pci_dev * pdev, unsigned int cmd, unsigned long arg)
{
	int retval = 0; /* return value of this call is the number of boards */
	
    /* this command returns an area of size CONFIG_APCI1032_MAX_BOARD_NBR+1 filled with the PCI_SLOT() value and as last field the major number associated to the device - this is deprecated and should not be used anymore.
	The call returns 0 when memory is too low or the number of boards  */	
   
	char * b_SlotArray = kmalloc(CONFIG_APCI1032_MAX_BOARD_NBR+1 * sizeof(char),GFP_KERNEL);
    if (!b_SlotArray)
	{
		/* bad param. Let output some information for debug */
		printk("%s: CMD_APCI1032_CheckAndGetPCISlotNumber: -EINVAL\n",__DRIVER_NAME);
		return 0;
	}
	    
	memset(b_SlotArray,0,CONFIG_APCI1032_MAX_BOARD_NBR+1 );

	printk("%s: the use of CMD_APCI1032_CheckAndGetPCISlotNumber is deprecated\n",__DRIVER_NAME);

	/* record the PCI_SLOT for each device from 0 to CONFIG_APCI1032_MAX_BOARD_NBR  */
	{	    	
		int i;
		for(i = 0; ( ( i < atomic_read(&apci1032_count) ) || ( i< CONFIG_APCI1032_MAX_BOARD_NBR ) ); i++)
		{
			
			struct pci_dev * dev =  apci1032_lookup_board_by_index(i);
			
			if (!dev) break;
			
			b_SlotArray[i] = PCI_SLOT(dev->devfn);
			
		}
    }
    b_SlotArray[CONFIG_APCI1032_MAX_BOARD_NBR] = apci1032_majornumber;

    if ( copy_to_user ( (unsigned char __user *)arg, b_SlotArray, (CONFIG_APCI1032_MAX_BOARD_NBR+1)) )
	{
    	/* bad address. Let output some information for debug */
    	printk("%s: CMD_APCI1032_CheckAndGetPCISlotNumber: -EFAULT\n",__DRIVER_NAME);
    	kfree(b_SlotArray);
    	return 0;
	}
	/* return the smaller value between CONFIG_APCI1032_MAX_BOARD_NBR and number of board - Note: apci1032_count is assumed to to be always consistent with the system PCI devices list */
    retval = ( atomic_read(&apci1032_count) < CONFIG_APCI1032_MAX_BOARD_NBR ? atomic_read(&apci1032_count) : CONFIG_APCI1032_MAX_BOARD_NBR );

	kfree(b_SlotArray);	            	
	
	return retval;	

}



//------------------------------------------------------------------------------
/** Returns the informations of base address, IRQ to the user.
 * @deprecated: use-space doesn't need it and kernel-space has better means to get it.
 *  */
int do_CMD_APCI1032_GetHardwareInformation(struct pci_dev * pdev, unsigned int cmd, unsigned long arg)
{
	str_BaseInformations s_BaseInformations;
	s_BaseInformations.ui_BaseAddress[0] = GET_BAR0(pdev);
	s_BaseInformations.ui_BaseAddress[1] = GET_BAR1(pdev);
	s_BaseInformations.ui_BaseAddress[2] = 0;
	s_BaseInformations.ui_BaseAddress[3] = 0;
	s_BaseInformations.ui_BaseAddress[4] = 0;
	s_BaseInformations.b_Interrupt = pdev->irq;
	s_BaseInformations.b_SlotNumber = PCI_SLOT(pdev->devfn);

    if ( copy_to_user ((str_BaseInformations __user *)arg,&s_BaseInformations, sizeof(s_BaseInformations)) )
		return -EFAULT;
	
	return 0;
}

//------------------------------------------------------------------------------
int do_CMD_APCI1032_SetBoardInformation(struct pci_dev * pdev, unsigned int cmd, unsigned long arg)
{
	return 0;
}
