⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 icp_multi.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    comedi/drivers/icp_multi.c    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1997-2002 David A. Schleef <ds@schleef.org>    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., 675 Mass Ave, Cambridge, MA 02139, USA.*//*Driver: icp_multi.oDescription: Inova ICP_MULTIAuthor: Anne Smorthit <anne.smorthit@sfwte.ch>Devices: [Inova] ICP_MULTI (icp_multi)Status: worksThe driver works for analog input and output and digital input and output.It does not work with interrupts or with the counters.  Currently no supportfor DMA.It has 16 single-ended or 8 differential Analogue Input channels with 12-bitresolution.  Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA.  Inputranges can be individually programmed for each channel.  Voltage or currentmeasurement is selected by jumper.There are 4 x 12-bit Analogue Outputs.  Ranges : 5V, 10V, +/-5V, +/-10V16 x Digital Inputs, 24V8 x Digital Outputs, 24V, 1A4 x 16-bit countersOptions: [0] - PCI bus number - if bus number and slot number are 0,                         then driver search for first unused card [1] - PCI slot number */#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/pci.h>#include "icp_multi.h"#define DEVICE_ID	0x8000	/* Device ID */#define ICP_MULTI_EXTDEBUG// Hardware types of the cards#define TYPE_ICP_MULTI	0#define IORANGE_ICP_MULTI 	32		#define ICP_MULTI_ADC_CSR	0	/* R/W:	ADC command/status register */#define ICP_MULTI_AI		2	/* R:	Analogue input data */#define ICP_MULTI_DAC_CSR	4	/* R/W:	DAC command/status register */#define ICP_MULTI_AO		6	/* R/W:	Analogue output data */#define ICP_MULTI_DI		8	/* R/W:	Digital inouts */#define ICP_MULTI_DO		0x0A	/* R/W:	Digital outputs */#define ICP_MULTI_INT_EN	0x0C	/* R/W:	Interrupt enable register */#define ICP_MULTI_INT_STAT	0x0E	/* R/W:	Interrupt status register */#define ICP_MULTI_CNTR0		0x10	/* R/W:	Counter 0 */#define ICP_MULTI_CNTR1		0x12	/* R/W:	counter 1 */#define ICP_MULTI_CNTR2		0x14	/* R/W:	Counter 2 */#define ICP_MULTI_CNTR3		0x16	/* R/W:	Counter 3 */#define ICP_MULTI_SIZE		0x20	/* 32 bytes */// Define bits from ADC command/status register#define	ADC_ST		0x0001		/* Start ADC */#define	ADC_BSY		0x0001		/* ADC busy */#define ADC_BI		0x0010		/* Bipolar input range 1 = bipolar */#define ADC_RA		0x0020		/* Input range 0 = 5V, 1 = 10V */#define	ADC_DI		0x0040		/* Differential input mode 1 = differential */// Define bits from DAC command/status register#define	DAC_ST		0x0001		/* Start DAC */#define DAC_BSY		0x0001		/* DAC busy */#define	DAC_BI		0x0010		/* Bipolar input range 1 = bipolar */#define	DAC_RA		0x0020		/* Input range 0 = 5V, 1 = 10V */// Define bits from interrupt enable/status registers#define	ADC_READY	0x0001		/* A/d conversion ready interrupt */#define	DAC_READY	0x0002		/* D/a conversion ready interrupt */#define	DOUT_ERROR	0x0004		/* Digital output error interrupt */#define	DIN_STATUS	0x0008		/* Digital input status change interrupt */#define	CIE0		0x0010		/* Counter 0 overrun interrupt */#define	CIE1		0x0020		/* Counter 1 overrun interrupt */#define	CIE2		0x0040		/* Counter 2 overrun interrupt */#define	CIE3		0x0080		/* Counter 3 overrun interrupt */// Useful definitions#define	Status_IRQ	0x00ff		// All interrupts// Define analogue rangestatic comedi_lrange range_analog={ 4, {	UNI_RANGE(5),	UNI_RANGE(10),	BIP_RANGE(5),	BIP_RANGE(10)	}};static char range_codes_analog[]={0x00, 0x20, 0x10, 0x30};/*==============================================================================	Forward declarations==============================================================================*/static int icp_multi_attach(comedi_device *dev, comedi_devconfig *it);static int icp_multi_detach(comedi_device *dev);/*==============================================================================	Data & Structure declarations==============================================================================*/static unsigned short	pci_list_builded=0;	/*=1 list of card is know */typedef struct {	char 		*name;		// driver name	int		device_id;	int		iorange;	// I/O range len	char		have_irq;	// 1=card support IRQ	char		cardtype;	// 0=ICP Multi	int 		n_aichan;	// num of A/D chans	int 		n_aichand;	// num of A/D chans in diff mode	int 		n_aochan;	// num of D/A chans	int 		n_dichan;	// num of DI chans	int 		n_dochan;	// num of DO chans	int		n_ctrs;		// num of counters	int		ai_maxdata;	// resolution of A/D	int		ao_maxdata;	// resolution of D/A	comedi_lrange	*rangelist_ai;	// rangelist for A/D	char		*rangecode;	// range codes for programming	comedi_lrange	*rangelist_ao;	// rangelist for D/A} boardtype;static boardtype boardtypes[] ={	{"icp_multi",		// Driver name	 DEVICE_ID,		// PCI device ID	 IORANGE_ICP_MULTI,	// I/O range length	 1,			// 1=Card supports interrupts	 TYPE_ICP_MULTI,	// Card type = ICP MULTI	 16,			// Num of A/D channels	 8,			// Num of A/D channels in diff mode	 4,			// Num of D/A channels	 16,			// Num of digital inputs	 8,			// Num of digital outputs	 4,			// Num of counters	 0x0fff,		// Resolution of A/D	 0x0fff,		// Resolution of D/A	 &range_analog,		// Rangelist for A/D	 range_codes_analog,	// Range codes for programming	 &range_analog },	// Rangelist for D/A};#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))static comedi_driver driver_icp_multi={	driver_name:	"icp_multi",	module:		THIS_MODULE,	attach:		icp_multi_attach,	detach:		icp_multi_detach,	num_names:	n_boardtypes,	board_name:	boardtypes,	offset:		sizeof(boardtype),	};COMEDI_INITCLEANUP(driver_icp_multi);typedef struct{	char			valid;			// card is usable	void			*io_addr;		// Pointer to mapped io address	unsigned long		phys_iobase;		// Physical io address	unsigned int		AdcCmdStatus;		// ADC Command/Status register	unsigned int		DacCmdStatus;		// DAC Command/Status register	unsigned int		IntEnable;		// Interrupt Enable register	unsigned int		IntStatus;		// Interrupt Status register	unsigned int		act_chanlist[32];	// list of scaned channel	unsigned char		act_chanlist_len;	// len of scanlist	unsigned char 		act_chanlist_pos;	// actual position in MUX list	unsigned int		*ai_chanlist;		// actaul chanlist	sampl_t			*ai_data;		// data buffer	sampl_t			ao_data[4];		// data output buffer	sampl_t			di_data;		// Digital input data	unsigned int		do_data;		// Remember digital output data} icp_multi_private;#define devpriv ((icp_multi_private *)dev->private)#define this_board ((boardtype *)dev->board_ptr)/* ==============================================================================	More forward declarations==============================================================================*/#if 0static int check_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan);#endifstatic void setup_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan);static int icp_multi_reset(comedi_device *dev);/* ==============================================================================	Functions==============================================================================*//*==============================================================================	Name:	icp_multi_insn_read_ai	Description:		This function reads a single analogue input.	Parameters:		comedi_device *dev	Pointer to current device structure		comedi_subdevice *s	Pointer to current subdevice structure		comedi_insn *insn	Pointer to current comedi instruction		lsampl_t *data		Pointer to analogue input data	Returns:int			Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_read_ai(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data){	int n,timeout;#ifdef ICP_MULTI_EXTDEBUG	printk("icp multi EDBG: BGN: icp_multi_insn_read_ai(...)\n");#endif	// Disable A/D conversion ready interrupt	devpriv->IntEnable &= ~ADC_READY;	writew(devpriv->IntEnable,dev->iobase + ICP_MULTI_INT_EN);		// Clear interrupt status	devpriv->IntStatus |= ADC_READY;	writew(devpriv->IntStatus,dev->iobase + ICP_MULTI_INT_STAT);	// Set up appropriate channel, mode and range data, for specified channel	setup_channel_list(dev, s, &insn->chanspec, 1);#ifdef ICP_MULTI_EXTDEBUG	printk("icp_multi A ST=%4x IO=%x\n",readw(dev->iobase+ICP_MULTI_ADC_CSR), dev->iobase+ICP_MULTI_ADC_CSR);#endif	for (n=0; n<insn->n; n++) {		// Set start ADC bit		devpriv->AdcCmdStatus |= ADC_ST;		writew(devpriv->AdcCmdStatus, dev->iobase+ICP_MULTI_ADC_CSR);		devpriv->AdcCmdStatus &= ~ADC_ST;#ifdef ICP_MULTI_EXTDEBUG    		printk("icp multi B n=%d ST=%4x\n",n,readw(dev->iobase+ICP_MULTI_ADC_CSR));#endif		comedi_udelay(1);#ifdef ICP_MULTI_EXTDEBUG    		printk("icp multi C n=%d ST=%4x\n",n,readw(dev->iobase+ICP_MULTI_ADC_CSR));#endif		// Wait for conversion to complete, or get fed up waiting    		timeout=100;    		while (timeout--) {			if (!(readw(dev->iobase+ICP_MULTI_ADC_CSR) & ADC_BSY))				goto conv_finish;#ifdef ICP_MULTI_EXTDEBUG			if (!(timeout%10))				printk("icp multi D n=%d tm=%d ST=%4x\n",n,timeout,readw(dev->iobase+ICP_MULTI_ADC_CSR));#endif			comedi_udelay(1);    		}		// If we reach here, a timeout has occurred    		comedi_error(dev,"A/D insn timeout");		// Disable interrupt		devpriv->IntEnable &= ~ADC_READY;		writew(devpriv->IntEnable,dev->iobase + ICP_MULTI_INT_EN);		// Clear interrupt status		devpriv->IntStatus |= ADC_READY;		writew(devpriv->IntStatus,dev->iobase + ICP_MULTI_INT_STAT);		// Clear data received    		data[n]=0;#ifdef ICP_MULTI_EXTDEBUG		printk("icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n",n);#endif    		return -ETIME;conv_finish:		data[n] = (readw(dev->iobase+ICP_MULTI_AI) >> 4 ) & 0x0fff;	}		// Disable interrupt	devpriv->IntEnable &= ~ADC_READY;	writew(devpriv->IntEnable,dev->iobase + ICP_MULTI_INT_EN);	// Clear interrupt status	devpriv->IntStatus |= ADC_READY;	writew(devpriv->IntStatus,dev->iobase + ICP_MULTI_INT_STAT);#ifdef ICP_MULTI_EXTDEBUG		printk("icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n",n);#endif	return n;}/*==============================================================================		Name:	icp_multi_insn_write_ao	Description:		This function writes a single analogue output.	Parameters:		comedi_device *dev	Pointer to current device structure		comedi_subdevice *s	Pointer to current subdevice structure		comedi_insn *insn	Pointer to current comedi instruction		lsampl_t *data		Pointer to analogue output data	Returns:int			Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_write_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data){	int n, chan, range, timeout;#ifdef ICP_MULTI_EXTDEBUG	printk("icp multi EDBG: BGN: icp_multi_insn_write_ao(...)\n");#endif	// Disable D/A conversion ready interrupt	devpriv->IntEnable &= ~DAC_READY;	writew(devpriv->IntEnable,dev->iobase + ICP_MULTI_INT_EN);		// Clear interrupt status	devpriv->IntStatus |= DAC_READY;	writew(devpriv->IntStatus,dev->iobase + ICP_MULTI_INT_STAT);	// Get channel number and range	chan = CR_CHAN(insn->chanspec);	range = CR_RANGE(insn->chanspec);	// Set up range and channel data	// Bit 4 = 1 : Bipolar	// Bit 5 = 0 : 5V	// Bit 5 = 1 : 10V	// Bits 8-9 : Channel number	devpriv->DacCmdStatus &= 0xfccf;	devpriv->DacCmdStatus |= this_board->rangecode[range];	devpriv->DacCmdStatus |= (chan << 8);		writew(devpriv->DacCmdStatus, dev->iobase+ICP_MULTI_DAC_CSR);	for (n=0; n<insn->n; n++) {		// Wait for analogue output data register to be ready for new data, or get fed up waiting    		timeout=100;    		while (timeout--) {			if (!(readw(dev->iobase+ICP_MULTI_DAC_CSR) & DAC_BSY))				goto dac_ready;#ifdef ICP_MULTI_EXTDEBUG			if (!(timeout%10))				printk("icp multi A n=%d tm=%d ST=%4x\n",n,timeout,readw(dev->iobase+ICP_MULTI_DAC_CSR));#endif			comedi_udelay(1);    		}		// If we reach here, a timeout has occurred    		comedi_error(dev,"D/A insn timeout");		// Disable interrupt		devpriv->IntEnable &= ~DAC_READY;		writew(devpriv->IntEnable,dev->iobase + ICP_MULTI_INT_EN);		// Clear interrupt status		devpriv->IntStatus |= DAC_READY;		writew(devpriv->IntStatus,dev->iobase + ICP_MULTI_INT_STAT);		// Clear data received    		devpriv->ao_data[chan]=0;#ifdef ICP_MULTI_EXTDEBUG		printk("icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n",n);#endif    		return -ETIME;dac_ready:		// Write data to analogue output data register		writew(data[n], dev->iobase + ICP_MULTI_AO);		// Set DAC_ST bit to write the data to selected channel		devpriv->DacCmdStatus |= DAC_ST;		writew(devpriv->DacCmdStatus, dev->iobase+ICP_MULTI_DAC_CSR);		devpriv->DacCmdStatus &= ~DAC_ST;		// Save analogue output data		devpriv->ao_data[chan]=data[n];	}#ifdef ICP_MULTI_EXTDEBUG		printk("icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n",n);#endif		return n;}/*==============================================================================		Name:	icp_multi_insn_read_ao	Description:		This function reads a single analogue output.	Parameters:		comedi_device *dev	Pointer to current device structure		comedi_subdevice *s	Pointer to current subdevice structure		comedi_insn *insn	Pointer to current comedi instruction		lsampl_t *data		Pointer to analogue output data	Returns:int			Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_read_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data){	int n,chan;	// Get channel number		chan = CR_CHAN(insn->chanspec);	// Read analogue outputs	for (n=0; n<insn->n; n++) 		data[n]=devpriv->ao_data[chan];	return n;}/*==============================================================================		Name:	icp_multi_insn_bits_di	Description:		This function reads the digital inputs.	Parameters:		comedi_device *dev	Pointer to current device structure		comedi_subdevice *s	Pointer to current subdevice structure		comedi_insn *insn	Pointer to current comedi instruction		lsampl_t *data		Pointer to analogue output data	Returns:int			Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_bits_di(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){	data[1] = readw(dev->iobase + ICP_MULTI_DI);	return 2;}/*==============================================================================		Name:	icp_multi_insn_bits_do	Description:		This function writes the appropriate digital outputs.	Parameters:		comedi_device *dev	Pointer to current device structure		comedi_subdevice *s	Pointer to current subdevice structure		comedi_insn *insn	Pointer to current comedi instruction		lsampl_t *data		Pointer to analogue output data	Returns:int			Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_bits_do(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){#ifdef ICP_MULTI_EXTDEBUG	printk("icp multi EDBG: BGN: icp_multi_insn_bits_do(...)\n");#endif	if (data[0]) {		s->state &= ~data[0];		s->state |= (data[0] & data[1]);		printk("Digital outputs = %4x \n", s->state);		writew(s->state, dev->iobase + ICP_MULTI_DO);	}	data[1] = readw(dev->iobase + ICP_MULTI_DI);#ifdef ICP_MULTI_EXTDEBUG		printk("icp multi EDBG: END: icp_multi_insn_bits_do(...)\n");#endif	return 2;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -