/** @par LICENCE
* @verbatim
Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
        
        ADDI-DATA GmbH
        Airpark Business Center
        Airport Boulevard B210
        77836 Rheinmünster
        Germany
        Tel: +49(0)7229/1847-0
        
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 "apcie1564-private.h"

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

//------------------------------------------------------------------------------
int apcie1564_do_ioctl(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	switch(cmd)
	{    
	
		case CMD_APCIE1564_CheckAndGetPCISlotNumber:
			return do_CMD_APCIE1564_CheckAndGetPCISlotNumber(pdev,cmd,arg);
			break;
		
		case CMD_APCIE1564_SetBoardInformation:
			return do_CMD_APCIE1564_SetBoardInformation(pdev,cmd,arg);
			break;
								
		
		case CMD_APCIE1564_GetHardwareInformation:
			return do_CMD_APCIE1564_GetHardwareInformation(pdev,cmd,arg);
			break; 
		
		/* DIGITAL INPUT */	
		case CMD_APCIE1564_Read32DigitalInput:
			return do_CMD_APCIE1564_Read32DigitalInput(pdev,cmd,arg);
			break;
		
		case CMD_APCIE1564_ClearAndStopDigitalInputInterrupt:
			return do_CMD_APCIE1564_ClearAndStopDigitalInputInterrupt(pdev,cmd,arg);
			break;
			
		case CMD_APCIE1564_InitAndStartDigitalInputInterrupt:
			return do_CMD_APCIE1564_InitAndStartDigitalInputInterrupt(pdev,cmd,arg);
			break;
			
		case CMD_APCIE1564_GetDigitalInputInterruptConfig:
			return do_CMD_APCIE1564_GetDigitalInputInterruptConfig(pdev,cmd,arg);
			break;
			
		/* DIGITAL OUTPUT */
        case CMD_APCIE1564_Read32DigitalOutput:
            return do_CMD_APCIE1564_Read32DigitalOutput(pdev,cmd,arg);
            break;
				
		case CMD_APCIE1564_Set32DigitalOutputOn:
			return do_CMD_APCIE1564_Set32DigitalOutputOn(pdev,cmd,arg);
			break;                              
		
		case CMD_APCIE1564_Set32DigitalOutputOff:
			return do_CMD_APCIE1564_Set32DigitalOutputOff(pdev,cmd,arg);
			break;                              
		
		case CMD_APCIE1564_SetOutputMemoryOn:
			return do_CMD_APCIE1564_SetOutputMemoryOn(pdev,cmd,arg);
			break;                                                                		
		
		case CMD_APCIE1564_SetOutputMemoryOff:
			return do_CMD_APCIE1564_SetOutputMemoryOff(pdev,cmd,arg);
			break;
		
		/* EVENTS */
		case CMD_APCIE1564_EventEmpty:
			return do_CMD_APCIE1564_EventEmpty(pdev,cmd,arg);
			break;
			
		case CMD_APCIE1564_EventWait:
			return do_CMD_APCIE1564_EventWait(pdev,cmd,arg);
			break;

		/* COUNTER */
		case CMD_APCIE1564_CounterInitAndStart:
			return do_CMD_APCIE1564_CounterInitAndStart(pdev, cmd, arg);
			break;
		
		case CMD_APCIE1564_ReadCounterValue:
			return do_CMD_APCIE1564_ReadCounterValue(pdev, cmd, arg);
			break;
				
		case CMD_APCIE1564_CounterStop:
			return do_CMD_APCIE1564_CounterStop(pdev, cmd, arg);
			break;
		
		case CMD_APCIE1564_CounterGetStatus:
			return do_CMD_APCIE1564_CounterGetStatus(pdev, cmd, arg);
			break;

		case CMD_APCIE1564_CounterGetConfigRegister:
			return do_CMD_APCIE1564_CounterGetConfigRegister(pdev, cmd, arg);
			break;
		case CMD_APCIE1564_CounterReset:
			return do_CMD_APCIE1564_CounterReset(pdev, cmd, arg);
			break;
		case CMD_APCIE1564_CounterTrigger:
			return do_CMD_APCIE1564_CounterTrigger(pdev, cmd, arg);
			break;
		default:
			return -EINVAL;
	}

}

//------------------------------------------------------------------------------
int do_CMD_APCIE1564_CheckAndGetPCISlotNumber(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	/* this command returns an area of size CONFIG_APCIE1564_MAX_BOARD_NBR+1 filled with the PCI_SLOT() value and as last field the major number associated to thepdevice - 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_APCIE1564_MAX_BOARD_NBR+1 * sizeof(char),GFP_KERNEL);
	if (!b_SlotArray)
	{
		/* bad param. Let output some information for debug */
		printk("%s: CMD_APCIE1564_CheckAndGetPCISlotNumber: -EINVAL\n",__DRIVER_NAME);
		return 0;
	}
		
	memset(b_SlotArray,0,CONFIG_APCIE1564_MAX_BOARD_NBR+1 );
	
	printk("%s: the use of CMD_APCIE1564_CheckAndGetPCISlotNumber is deprecated\n",__DRIVER_NAME);
	
	/* record the PCI_SLOT for eachpdevice from 0 to CONFIG_APCIE1564_MAX_BOARD_NBR  */
	{	    	
		int i;
		for(i = 0; ( ( i < atomic_read(&apcie1564_count) ) || ( i< CONFIG_APCIE1564_MAX_BOARD_NBR ) ); i++)
		{
			
			struct pci_dev * tmpdev =  apcie1564_lookup_board_by_index(i);
			
			if (!tmpdev) break;
			
			b_SlotArray[i] = PCI_SLOT(tmpdev->devfn);
			
		}
	}
	b_SlotArray[CONFIG_APCIE1564_MAX_BOARD_NBR] = apcie1564_majornumber;
	
	if ( copy_to_user ( (uint8_t __user *)arg, 
			b_SlotArray,
			sizeof (uint8_t[CONFIG_APCIE1564_MAX_BOARD_NBR+1])) )
	{
		/* bad address. Let output some information for debug */
		printk("%s: CMD_APCIE1564_CheckAndGetPCISlotNumber: -EFAULT\n",__DRIVER_NAME);
		kfree(b_SlotArray);
		return 0;
	}
	
	kfree(b_SlotArray);
	
	/* return the smaller value between CONFIG_APCIE1564_MAX_BOARD_NBR and number of board - Note: apcie1564_count is assumed to to be always consistent with the system PCIpdevices list */
	return ( atomic_read(&apcie1564_count) < CONFIG_APCIE1564_MAX_BOARD_NBR ? atomic_read(&apcie1564_count) : CONFIG_APCIE1564_MAX_BOARD_NBR );
				
}	

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

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

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

int do_CMD_APCIE1564_GetHardwareInformation(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	str_BaseInformations s_BaseInformations;
	s_BaseInformations.ui_BaseAddress[0] = 0;
	s_BaseInformations.ui_BaseAddress[1] = GET_BAR1(pdev);
	s_BaseInformations.ui_BaseAddress[2] = 0;
	s_BaseInformations.ui_BaseAddress[3] = GET_BAR3(pdev);
	s_BaseInformations.ui_BaseAddress[4] = 0;
	s_BaseInformations.b_Interrupt =pdev->irq;
	s_BaseInformations.b_SlotNumber = PCI_SLOT(pdev->devfn);
	/* Returns the informations of base address, IRQ */
	/* to the user */
	if ( copy_to_user ((str_BaseInformations __user *)arg,&s_BaseInformations, sizeof(s_BaseInformations)) )
		return -EFAULT;
		
	return 0;
}
