/** @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 should also find the complete GPL in the COPYING file accompanying this source code. @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 : API APCI1710 | Compiler : gcc | | Module name : SSI.C | Version : 2.96 | +-------------------------------+---------------------------------------+ | Project manager: Eric Stolz | Date : 02/12/2002 | +-----------------------------------------------------------------------+ | Description : APCI-1710 SSI counter module | +-----------------------------------------------------------------------+ | several changes done by S. Weber in 1998 and C. Guinot in 2000 | +-----------------------------------------------------------------------+ */ #define APCI1710_30MHZ 30 #define APCI1710_33MHZ 33 #define APCI1710_40MHZ 40 #define APCI1710_BINARY_MODE 0x1 #define APCI1710_GRAY_MODE 0x0 #define APCI1710_SSI_READ1VALUE 1 #define APCI1710_SSI_READALLVALUE 2 #define APCI1710_SSI_SET_CHANNELON 0 #define APCI1710_SSI_SET_CHANNELOFF 1 #define APCI1710_SSI_READ_1CHANNEL 2 #define APCI1710_SSI_READ_ALLCHANNEL 3 /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitSSI | | (unsigned char_ b_BoardHandle, | | unsigned char_ b_ModulNbr, | | unsigned char_ b_SSIProfile, | | unsigned char_ b_PositionTurnLength, | | unsigned char_ b_TurnCptLength, | | unsigned char_ b_PCIInputClock, | | ULONG_ ul_SSIOutputClock, | | unsigned char_ b_SSICountingMode) | +----------------------------------------------------------------------------+ | Task : Configure the SSI operating mode from selected module | | (b_ModulNbr). You must calling this function be for you| | call any other function witch access of SSI. | +----------------------------------------------------------------------------+ | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| | unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | | unsigned char_ b_SSIProfile : Selection from SSI | | profile length (2 to 32).| | unsigned char_ b_PositionTurnLength : Selection from SSI | | position data length | | (1 to 31). | | unsigned char_ b_TurnCptLength : Selection from SSI turn | | counter data length | | (1 to 31). | | unsigned char b_PCIInputClock : Selection from PCI bus | | clock | | - APCI1710_30MHZ : | | The PC have a PCI bus | | clock from 30 MHz | | - APCI1710_33MHZ : | | The PC have a PCI bus | | clock from 33 MHz | | ULONG_ ul_SSIOutputClock : Selection from SSI output| | clock. | | From 229 to 5 000 000 Hz| | for 30 MHz selection. | | From 252 to 5 000 000 Hz| | for 33 MHz selection. | | unsigned char b_SSICountingMode : SSI counting mode | | selection | | - APCI1710_BINARY_MODE : | | Binary counting mode. | | - APCI1710_GRAY_MODE : | | Gray counting mode. b_ModulNbr = CR_AREF(insn->chanspec); b_SSIProfile = (unsigned char) data[0]; b_PositionTurnLength= (unsigned char) data[1]; b_TurnCptLength = (unsigned char) data[2]; b_PCIInputClock = (unsigned char) data[3]; ul_SSIOutputClock = (unsigned int) data[4]; b_SSICountingMode = (unsigned char) data[5]; | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | | -2: The module parameter is wrong | | -3: The module is not a SSI module | | -4: The selected SSI profile length is wrong | | -5: The selected SSI position data length is wrong | | -6: The selected SSI turn counter data length is wrong | | -7: The selected PCI input clock is wrong | | -8: The selected SSI output clock is wrong | | -9: The selected SSI counting mode parameter is wrong | +----------------------------------------------------------------------------+ */ static int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; int i_ReturnValue = 0; unsigned int ui_TimerValue; unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength, b_PCIInputClock, b_SSICountingMode; unsigned int ul_SSIOutputClock; b_ModulNbr = CR_AREF(insn->chanspec); b_SSIProfile = (unsigned char) data[0]; b_PositionTurnLength = (unsigned char) data[1]; b_TurnCptLength = (unsigned char) data[2]; b_PCIInputClock = (unsigned char) data[3]; ul_SSIOutputClock = (unsigned int) data[4]; b_SSICountingMode = (unsigned char) data[5]; i_ReturnValue = insn->n; /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { /***********************/ /* Test if SSI counter */ /***********************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { /*******************************/ /* Test the SSI profile length */ /*******************************/ /* CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */ if (b_SSIProfile >= 2 && b_SSIProfile < 33) { /*************************************/ /* Test the SSI position data length */ /*************************************/ if (b_PositionTurnLength > 0 && b_PositionTurnLength < 32) { /*****************************************/ /* Test the SSI turn counter data length */ /*****************************************/ if (b_TurnCptLength > 0 && b_TurnCptLength < 32) { /***************************/ /* Test the profile length */ /***************************/ if ((b_TurnCptLength + b_PositionTurnLength) <= b_SSIProfile) { /****************************/ /* Test the PCI input clock */ /****************************/ if (b_PCIInputClock == APCI1710_30MHZ || b_PCIInputClock == APCI1710_33MHZ) { /*************************/ /* Test the output clock */ /*************************/ if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) { if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) { /**********************/ /* Save configuration */ /**********************/ devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile = b_SSIProfile; devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength = b_PositionTurnLength; devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_TurnCptLength = b_TurnCptLength; /*********************************/ /* Initialise the profile length */ /*********************************/ if (b_SSICountingMode == APCI1710_BINARY_MODE) { outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); } else { outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); } /******************************/ /* Calculate the output clock */ /******************************/ ui_TimerValue = (unsigned int) ( ((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock); /************************/ /* Initialise the timer */ /************************/ outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); /********************************/ /* Initialise the counting mode */ /********************************/ outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIInit = 1; } else { /*****************************************************/ /* The selected SSI counting mode parameter is wrong */ /*****************************************************/ DPRINTK("The selected SSI counting mode parameter is wrong\n"); i_ReturnValue = -9; } } else { /******************************************/ /* The selected SSI output clock is wrong */ /******************************************/ DPRINTK("The selected SSI output clock is wrong\n"); i_ReturnValue = -8; } } else { /*****************************************/ /* The selected PCI input clock is wrong */ /*****************************************/ DPRINTK("The selected PCI input clock is wrong\n"); i_ReturnValue = -7; } } else { /********************************************/ /* The selected SSI profile length is wrong */ /********************************************/ DPRINTK("The selected SSI profile length is wrong\n"); i_ReturnValue = -4; } } else { /******************************************************/ /* The selected SSI turn counter data length is wrong */ /******************************************************/ DPRINTK("The selected SSI turn counter data length is wrong\n"); i_ReturnValue = -6; } } else { /**************************************************/ /* The selected SSI position data length is wrong */ /**************************************************/ DPRINTK("The selected SSI position data length is wrong\n"); i_ReturnValue = -5; } } else { /********************************************/ /* The selected SSI profile length is wrong */ /********************************************/ DPRINTK("The selected SSI profile length is wrong\n"); i_ReturnValue = -4; } } else { /**********************************/ /* The module is not a SSI module */ /**********************************/ DPRINTK("The module is not a SSI module\n"); i_ReturnValue = -3; } } else { /***********************/ /* Module number error */ /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Read1SSIValue | | (unsigned char_ b_BoardHandle, | | unsigned char_ b_ModulNbr, | | unsigned char_ b_SelectedSSI, | | PULONG_ pul_Position, | | PULONG_ pul_TurnCpt) int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Read the selected SSI counter (b_SelectedSSI) from | | selected module (b_ModulNbr). or Read all SSI counter (b_SelectedSSI) from | | selected module (b_ModulNbr). | +----------------------------------------------------------------------------+ | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| | unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | | unsigned char_ b_SelectedSSI : Selection from SSI | | counter (0 to 2) b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi) b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_Position : SSI position in the turn | | PULONG_ pul_TurnCpt : Number of turns pul_Position = (unsigned int *) &data[0]; pul_TurnCpt = (unsigned int *) &data[1]; | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | | -2: The module parameter is wrong | | -3: The module is not a SSI module | | -4: SSI not initialised see function | | "i_APCI1710_InitSSI" | | -5: The selected SSI is wrong | +----------------------------------------------------------------------------+ */ static int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; int i_ReturnValue = 0; unsigned char b_Cpt; unsigned char b_Length; unsigned char b_Schift; unsigned char b_SSICpt; unsigned int dw_And; unsigned int dw_And1; unsigned int dw_And2; unsigned int dw_StatusReg; unsigned int dw_CounterValue; unsigned char b_ModulNbr; unsigned char b_SelectedSSI; unsigned char b_ReadType; unsigned int *pul_Position; unsigned int *pul_TurnCpt; unsigned int *pul_Position1; unsigned int *pul_TurnCpt1; i_ReturnValue = insn->n; pul_Position1 = (unsigned int *) &data[0]; /* For Read1 */ pul_TurnCpt1 = (unsigned int *) &data[1]; /* For Read all */ pul_Position = (unsigned int *) &data[0]; /* 0-2 */ pul_TurnCpt = (unsigned int *) &data[3]; /* 3-5 */ b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { /***********************/ /* Test if SSI counter */ /***********************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { /***************************/ /* Test if SSI initialised */ /***************************/ if (devpriv->s_ModuleInfo[b_ModulNbr]. s_SSICounterInfo.b_SSIInit == 1) { switch (b_ReadType) { case APCI1710_SSI_READ1VALUE: /****************************************/ /* Test the selected SSI counter number */ /****************************************/ if (b_SelectedSSI < 3) { /************************/ /* Start the conversion */ /************************/ outl(0, devpriv->s_BoardInfos. ui_Address + 8 + (64 * b_ModulNbr)); do { /*******************/ /* Read the status */ /*******************/ dw_StatusReg = inl(devpriv-> s_BoardInfos. ui_Address + (64 * b_ModulNbr)); } while ((dw_StatusReg & 0x1) != 0); /******************************/ /* Read the SSI counter value */ /******************************/ dw_CounterValue = inl(devpriv-> s_BoardInfos. ui_Address + 4 + (b_SelectedSSI * 4) + (64 * b_ModulNbr)); b_Length = devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile / 2; if ((b_Length * 2) != devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile) { b_Length++; } b_Schift = b_Length - devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; *pul_Position1 = dw_CounterValue >> b_Schift; dw_And = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; b_Cpt++) { dw_And = dw_And * 2; } *pul_Position1 = *pul_Position1 & ((dw_And) - 1); *pul_TurnCpt1 = dw_CounterValue >> b_Length; dw_And = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_TurnCptLength; b_Cpt++) { dw_And = dw_And * 2; } *pul_TurnCpt1 = *pul_TurnCpt1 & ((dw_And) - 1); } else { /*****************************/ /* The selected SSI is wrong */ /*****************************/ DPRINTK("The selected SSI is wrong\n"); i_ReturnValue = -5; } break; case APCI1710_SSI_READALLVALUE: dw_And1 = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo[b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; b_Cpt++) { dw_And1 = dw_And1 * 2; } dw_And2 = 1; for (b_Cpt = 0; b_Cpt < devpriv-> s_ModuleInfo[b_ModulNbr]. s_SSICounterInfo. b_TurnCptLength; b_Cpt++) { dw_And2 = dw_And2 * 2; } /************************/ /* Start the conversion */ /************************/ outl(0, devpriv->s_BoardInfos. ui_Address + 8 + (64 * b_ModulNbr)); do { /*******************/ /* Read the status */ /*******************/ dw_StatusReg = inl(devpriv-> s_BoardInfos. ui_Address + (64 * b_ModulNbr)); } while ((dw_StatusReg & 0x1) != 0); for (b_SSICpt = 0; b_SSICpt < 3; b_SSICpt++) { /******************************/ /* Read the SSI counter value */ /******************************/ dw_CounterValue = inl(devpriv-> s_BoardInfos. ui_Address + 4 + (b_SSICpt * 4) + (64 * b_ModulNbr)); b_Length = devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile / 2; if ((b_Length * 2) != devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_SSIProfile) { b_Length++; } b_Schift = b_Length - devpriv-> s_ModuleInfo [b_ModulNbr]. s_SSICounterInfo. b_PositionTurnLength; pul_Position[b_SSICpt] = dw_CounterValue >> b_Schift; pul_Position[b_SSICpt] = pul_Position[b_SSICpt] & ((dw_And1) - 1); pul_TurnCpt[b_SSICpt] = dw_CounterValue >> b_Length; pul_TurnCpt[b_SSICpt] = pul_TurnCpt[b_SSICpt] & ((dw_And2) - 1); } break; default: printk("Read Type Inputs Wrong\n"); } /* switch ending */ } else { /***********************/ /* SSI not initialised */ /***********************/ DPRINTK("SSI not initialised\n"); i_ReturnValue = -4; } } else { /**********************************/ /* The module is not a SSI module */ /**********************************/ DPRINTK("The module is not a SSI module\n"); i_ReturnValue = -3; } } else { /***********************/ /* Module number error */ /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadSSI1DigitalInput | | (unsigned char_ b_BoardHandle, | | unsigned char_ b_ModulNbr, | | unsigned char_ b_InputChannel, | | unsigned char *_ pb_ChannelStatus) | +----------------------------------------------------------------------------+ | Task : (0) Set the digital output from selected SSI module | | (b_ModuleNbr) ON (1) Set the digital output from selected SSI module | | (b_ModuleNbr) OFF (2)Read the status from selected SSI digital input | | (b_InputChannel) (3)Read the status from all SSI digital inputs from | | selected SSI module (b_ModulNbr) | +----------------------------------------------------------------------------+ | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| | unsigned char_ b_ModulNbr CR_AREF : Module number to | | configure (0 to 3) | | unsigned char_ b_InputChannel CR_CHAN : Selection from digital | | data[0] which IOTYPE input ( 0 to 2) | +----------------------------------------------------------------------------+ | Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel | | data[0] status | | 0 : Channle is not active| | 1 : Channle is active | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | | -2: The module parameter is wrong | | -3: The module is not a SSI module | | -4: The selected SSI digital input is wrong | +----------------------------------------------------------------------------+ */ static int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct addi_private *devpriv = dev->private; int i_ReturnValue = 0; unsigned int dw_StatusReg; unsigned char b_ModulNbr; unsigned char b_InputChannel; unsigned char *pb_ChannelStatus; unsigned char *pb_InputStatus; unsigned char b_IOType; i_ReturnValue = insn->n; b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); b_IOType = (unsigned char) data[0]; /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { /***********************/ /* Test if SSI counter */ /***********************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { switch (b_IOType) { case APCI1710_SSI_SET_CHANNELON: /*****************************/ /* Set the digital output ON */ /*****************************/ outl(1, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr)); break; case APCI1710_SSI_SET_CHANNELOFF: /******************************/ /* Set the digital output OFF */ /******************************/ outl(0, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr)); break; case APCI1710_SSI_READ_1CHANNEL: /******************************************/ /* Test the digital imnput channel number */ /******************************************/ b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); pb_ChannelStatus = (unsigned char *) &data[0]; if (b_InputChannel <= 2) { /**************************/ /* Read all digital input */ /**************************/ dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + (64 * b_ModulNbr)); *pb_ChannelStatus = (unsigned char) (((~dw_StatusReg) >> (4 + b_InputChannel)) & 1); } else { /********************************/ /* Selected digital input error */ /********************************/ DPRINTK("Selected digital input error\n"); i_ReturnValue = -4; } break; case APCI1710_SSI_READ_ALLCHANNEL: /**************************/ /* Read all digital input */ /**************************/ pb_InputStatus = (unsigned char *) &data[0]; dw_StatusReg = inl(devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); *pb_InputStatus = (unsigned char) (((~dw_StatusReg) >> 4) & 7); break; default: printk("IO type wrong\n"); } /* switch end */ } else { /**********************************/ /* The module is not a SSI module */ /**********************************/ DPRINTK("The module is not a SSI module\n"); i_ReturnValue = -3; } } else { /***********************/ /* Module number error */ /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } return i_ReturnValue; }