/** @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. @endverbatim */ /* +-----------------------------------------------------------------------+ | (C) ADDI-DATA GmbH Dieselstraße 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 : APCI-035 | Compiler : GCC | | Module name : hwdrv_apci035.c | Version : 2.96 | +-------------------------------+---------------------------------------+ | Project manager: Eric Stolz | Date : 02/12/2002 | +-------------------------------+---------------------------------------+ | Description : Hardware Layer Access For APCI-035 | +-----------------------------------------------------------------------+ | UPDATES | +----------+-----------+------------------------------------------------+ | Date | Author | Description of updates | +----------+-----------+------------------------------------------------+ | | | | | | | | | | | | +----------+-----------+------------------------------------------------+ */ /* Card Specific information */ #define APCI035_ADDRESS_RANGE 255 /* Timer / Watchdog Related Defines */ #define APCI035_TCW_SYNC_ENABLEDISABLE 0 #define APCI035_TCW_RELOAD_VALUE 4 #define APCI035_TCW_TIMEBASE 8 #define APCI035_TCW_PROG 12 #define APCI035_TCW_TRIG_STATUS 16 #define APCI035_TCW_IRQ 20 #define APCI035_TCW_WARN_TIMEVAL 24 #define APCI035_TCW_WARN_TIMEBASE 28 #define ADDIDATA_TIMER 0 /* #define ADDIDATA_WATCHDOG 1 */ #define APCI035_TW1 0 #define APCI035_TW2 32 #define APCI035_TW3 64 #define APCI035_TW4 96 #define APCI035_AI_OFFSET 0 #define APCI035_TEMP 128 #define APCI035_ALR_SEQ 4 #define APCI035_START_STOP_INDEX 8 #define APCI035_ALR_START_STOP 12 #define APCI035_ALR_IRQ 16 #define APCI035_EOS 20 #define APCI035_CHAN_NO 24 #define APCI035_CHAN_VAL 28 #define APCI035_CONV_TIME_TIME_BASE 36 #define APCI035_RELOAD_CONV_TIME_VAL 32 #define APCI035_DELAY_TIME_TIME_BASE 44 #define APCI035_RELOAD_DELAY_TIME_VAL 40 #define ENABLE_EXT_TRIG 1 #define ENABLE_EXT_GATE 2 #define ENABLE_EXT_TRIG_GATE 3 #define ANALOG_INPUT 0 #define TEMPERATURE 1 #define RESISTANCE 2 #define ADDIDATA_GREATER_THAN_TEST 0 #define ADDIDATA_LESS_THAN_TEST 1 #define APCI035_MAXVOLT 2.5 #define ADDIDATA_UNIPOLAR 1 #define ADDIDATA_BIPOLAR 2 /* ANALOG INPUT RANGE */ static struct comedi_lrange range_apci035_ai = { 8, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2), BIP_RANGE(1), UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2), UNI_RANGE(1) } }; static int i_WatchdogNbr = 0; static int i_Temp = 0; static int i_Flag = 1; /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_ConfigTimerWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Configures The Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Configure As Timer | | 1 Configure As Watchdog | | data[1] : Watchdog number | data[2] : Time base Unit | | data[3] : Reload Value | | data[4] : External Trigger | | 1:Enable | 0:Disable | data[5] :External Trigger Level | 00 Trigger Disabled | 01 Trigger Enabled (Low level) | 10 Trigger Enabled (High Level) | 11 Trigger Enabled (High/Low level) | data[6] : External Gate | | 1:Enable | 0:Disable | data[7] : External Gate level | 00 Gate Disabled | 01 Gate Enabled (Low level) | 10 Gate Enabled (High Level) | data[8] :Warning Relay | 1: ENABLE | 0: DISABLE | data[9] :Warning Delay available | data[10] :Warning Relay Time unit | data[11] :Warning Relay Time Reload value | data[12] :Reset Relay | 1 : ENABLE | 0 : DISABLE | data[13] :Interrupt | 1 : ENABLE | 0 : DISABLE | | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | | : FALSE : Error occur. Return the error | | | +----------------------------------------------------------------------------+ */ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Status = 0; unsigned int ui_Command = 0; unsigned int ui_Mode = 0; i_Temp = 0; devpriv->tsk_Current = current; devpriv->b_TimerSelectMode = data[0]; i_WatchdogNbr = data[1]; if (data[0] == 0) { ui_Mode = 2; } else { ui_Mode = 0; } /* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ ui_Command = 0; /* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /************************/ /* Set the reload value */ /************************/ outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); /*********************/ /* Set the time unit */ /*********************/ outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); if (data[0] == ADDIDATA_TIMER) { /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ /* - Disable the warning */ /* - Disable the reset */ /* - Enable the timer mode */ /* - Set the timer mode */ /******************************/ ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; } /* if (data[0] == ADDIDATA_TIMER) */ else { if (data[0] == ADDIDATA_WATCHDOG) { /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ /* - Disable the warning */ /* - Disable the reset */ /* - Disable the timer mode */ /******************************/ ui_Command = ui_Command & 0xFFF819E2UL; } else { printk("\n The parameter for Timer/watchdog selection is in error\n"); return -EINVAL; } } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /********************************/ /* Disable the hardware trigger */ /********************************/ ui_Command = ui_Command & 0xFFFFF89FUL; if (data[4] == ADDIDATA_ENABLE) { /**********************************/ /* Set the hardware trigger level */ /**********************************/ ui_Command = ui_Command | (data[5] << 5); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /*****************************/ /* Disable the hardware gate */ /*****************************/ ui_Command = ui_Command & 0xFFFFF87FUL; if (data[6] == ADDIDATA_ENABLE) { /*******************************/ /* Set the hardware gate level */ /*******************************/ ui_Command = ui_Command | (data[7] << 7); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /*******************************/ /* Disable the hardware output */ /*******************************/ ui_Command = ui_Command & 0xFFFFF9FBUL; /*********************************/ /* Set the hardware output level */ /*********************************/ ui_Command = ui_Command | (data[8] << 2); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); if (data[9] == ADDIDATA_ENABLE) { /************************/ /* Set the reload value */ /************************/ outl(data[11], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); /**********************/ /* Set the time unite */ /**********************/ outl(data[10], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); } ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /*******************************/ /* Disable the hardware output */ /*******************************/ ui_Command = ui_Command & 0xFFFFF9F7UL; /*********************************/ /* Set the hardware output level */ /*********************************/ ui_Command = ui_Command | (data[12] << 3); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /*************************************/ /** Enable the watchdog interrupt **/ /*************************************/ ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /*******************************/ /* Set the interrupt selection */ /*******************************/ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_StartStopWriteTimerWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Start / Stop The Selected Timer , or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 - Stop Selected Timer/Watchdog | | 1 - Start Selected Timer/Watchdog | | 2 - Trigger Selected Timer/Watchdog | | 3 - Stop All Timer/Watchdog | | 4 - Start All Timer/Watchdog | | 5 - Trigger All Timer/Watchdog | | | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | | : FALSE : Error occur. Return the error | | | +----------------------------------------------------------------------------+ */ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Command = 0; int i_Count = 0; if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /**********************/ /* Start the hardware */ /**********************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } /* if (data[0]==1) */ if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); /***************************/ /* Set the trigger command */ /***************************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } if (data[0] == 0) /* Stop The Watchdog */ { /* Stop The Watchdog */ ui_Command = 0; /* * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); * ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } /* if (data[1]==0) */ if (data[0] == 3) /* stop all Watchdogs */ { ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { ui_Command = 0x2UL; } else { ui_Command = 0x10UL; } i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } } if (data[0] == 4) /* start all Watchdogs */ { ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { ui_Command = 0x1UL; } else { ui_Command = 0x8UL; } i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } } if (data[0] == 5) /* trigger all Watchdogs */ { ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { ui_Command = 0x4UL; } else { ui_Command = 0x20UL; } i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } i_Temp = 1; } return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_ReadTimerWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Read The Selected Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | | +----------------------------------------------------------------------------+ | Output Parameters : data[0] : software trigger status | data[1] : hardware trigger status | data[2] : Software clear status | data[3] : Overflow status | data[4] : Timer actual value | +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | | : FALSE : Error occur. Return the error | | | +----------------------------------------------------------------------------+ */ static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Status = 0; /* Status register */ i_WatchdogNbr = insn->unused[0]; /******************/ /* Get the status */ /******************/ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); /***********************************/ /* Get the software trigger status */ /***********************************/ data[0] = ((ui_Status >> 1) & 1); /***********************************/ /* Get the hardware trigger status */ /***********************************/ data[1] = ((ui_Status >> 2) & 1); /*********************************/ /* Get the software clear status */ /*********************************/ data[2] = ((ui_Status >> 3) & 1); /***************************/ /* Get the overflow status */ /***************************/ data[3] = ((ui_Status >> 0) & 1); if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_ConfigAnalogInput | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Configures The Analog Input Subdevice | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s : Subdevice Pointer | | struct comedi_insn *insn : Insn Structure Pointer | | unsigned int *data : Data Pointer contains | | configuration parameters as below | | data[0] : Warning delay value | | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | | : FALSE : Error occur. Return the error | | | +----------------------------------------------------------------------------+ */ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); outl(0, devpriv->iobase + 128 + 0); /********************************/ /* Initialise the warning value */ /********************************/ outl(0x300 | 0, devpriv->iobase + 128 + 0x4); outl((data[0] << 8), devpriv->iobase + 128 + 0); outl(0x200000UL, devpriv->iobase + 128 + 12); return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_ReadAnalogInput | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Read value of the selected channel | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | unsigned int ui_NoOfChannels : No Of Channels To read | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : Digital Value Of Input | | | +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | | : FALSE : Error occur. Return the error | | | +----------------------------------------------------------------------------+ */ static int i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_CommandRegister = 0; /******************/ /* Set the start */ /******************/ ui_CommandRegister = 0x80000; /******************************/ /* Write the command register */ /******************************/ outl(ui_CommandRegister, devpriv->iobase + 128 + 8); /***************************************/ /* Read the digital value of the input */ /***************************************/ data[0] = inl(devpriv->iobase + 128 + 28); return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_Reset(struct comedi_device *dev) | | | +----------------------------------------------------------------------------+ | Task :Resets the registers of the card | +----------------------------------------------------------------------------+ | Input Parameters : | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ | Return Value : | | | +----------------------------------------------------------------------------+ */ static int i_APCI035_Reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_Count = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ } outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ return 0; } /* +----------------------------------------------------------------------------+ | Function Name : static void v_APCI035_Interrupt | | (int irq , void *d) | +----------------------------------------------------------------------------+ | Task : Interrupt processing Routine | +----------------------------------------------------------------------------+ | Input Parameters : int irq : irq number | | void *d : void pointer | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | | : FALSE : Error occur. Return the error | | | +----------------------------------------------------------------------------+ */ static void v_APCI035_Interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; unsigned int ui_StatusRegister1 = 0; unsigned int ui_StatusRegister2 = 0; unsigned int ui_ReadCommand = 0; unsigned int ui_ChannelNumber = 0; unsigned int ui_DigitalTemperature = 0; if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; } /**************************************/ /* Read the interrupt status register of temperature Warning */ /**************************************/ ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); /**************************************/ /* Read the interrupt status register for Watchdog/timer */ /**************************************/ ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */ { /**********************************/ /* Disable the temperature warning */ /**********************************/ ui_ReadCommand = inl(devpriv->iobase + 128 + 12); ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; outl(ui_ReadCommand, devpriv->iobase + 128 + 12); /***************************/ /* Read the channel number */ /***************************/ ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); /**************************************/ /* Read the digital temperature value */ /**************************************/ ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ else { if ((ui_StatusRegister2 & 0x1) == 0x1) { send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ } } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ return; }