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

📄 dt282x.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*   modules/dt282x.c   hardware driver for Data Translation DT2821 series   COMEDI - Linux Control and Measurement Device Interface   Copyright (C) 1997-8 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: dt282x.oDescription: Data Translation DT2821 series (including DT-EZ)Author: dsDevices: [Data Translation] DT2821 (dt2821), DT2823 (dt2823),  DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),  DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),  DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)Status: completeUpdated: Wed, 22 Aug 2001 17:11:34 -0700Configuration options:  [0] - I/O port base address  [1] - IRQ  [2] - DMA 1  [3] - DMA 2  [4] - AI jumpered for 0=single ended, 1=differential  [5] - AI jumpered for 0=straight binary, 1=2's complement  [6] - AO 0 jumpered for 0=straight binary, 1=2's complement  [7] - AO 1 jumpered for 0=straight binary, 1=2's complement  [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]  [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],        4=[-2.5,2.5]  [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],        4=[-2.5,2.5]Notes:  - AO commands might be broken.  - If you try to run a command on both the AI and AO subdevices    simultaneously, bad things will happen.  The driver needs to    be fixed to check for this situation and return an error.*/#include <linux/comedidev.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <asm/dma.h>#define DEBUG#define DT2821_TIMEOUT		100	/* 500 us */#define DT2821_SIZE 0x10/* *    Registers in the DT282x */#define DT2821_ADCSR	0x00	/* A/D Control/Status             */#define DT2821_CHANCSR	0x02	/* Channel Control/Status */#define DT2821_ADDAT	0x04	/* A/D data                       */#define DT2821_DACSR	0x06	/* D/A Control/Status             */#define DT2821_DADAT	0x08	/* D/A data                       */#define DT2821_DIODAT	0x0a	/* digital data                   */#define DT2821_SUPCSR	0x0c	/* Supervisor Control/Status      */#define DT2821_TMRCTR	0x0e	/* Timer/Counter          *//* *  At power up, some registers are in a well-known state.  The *  masks and values are as follows: */#define DT2821_ADCSR_MASK 0xfff0#define DT2821_ADCSR_VAL 0x7c00#define DT2821_CHANCSR_MASK 0xf0f0#define DT2821_CHANCSR_VAL 0x70f0#define DT2821_DACSR_MASK 0x7c93#define DT2821_DACSR_VAL 0x7c90#define DT2821_SUPCSR_MASK 0xf8ff#define DT2821_SUPCSR_VAL 0x0000#define DT2821_TMRCTR_MASK 0xff00#define DT2821_TMRCTR_VAL 0xf000/* *    Bit fields of each register *//* ADCSR */#define DT2821_ADERR	0x8000	/* (R)   1 for A/D error  */#define DT2821_ADCLK	0x0200	/* (R/W) A/D clock enable */		/*      0x7c00           read as 1's            */#define DT2821_MUXBUSY	0x0100	/* (R)   multiplexer busy */#define DT2821_ADDONE	0x0080	/* (R)   A/D done         */#define DT2821_IADDONE	0x0040	/* (R/W) interrupt on A/D done    */		/*      0x0030           gain select            */		/*      0x000f           channel select         *//* CHANCSR */#define DT2821_LLE	0x8000	/* (R/W) Load List Enable */		/*      0x7000           read as 1's            */		/*      0x0f00     (R)   present address        */		/*      0x00f0           read as 1's            */		/*      0x000f     (R)   number of entries - 1  *//* DACSR */#define DT2821_DAERR	0x8000	/* (R)   D/A error                */#define DT2821_YSEL	0x0200	/* (R/W) DAC 1 select             */#define DT2821_SSEL	0x0100	/* (R/W) single channel select    */#define DT2821_DACRDY	0x0080	/* (R)   DAC ready                */#define DT2821_IDARDY	0x0040	/* (R/W) interrupt on DAC ready   */#define DT2821_DACLK	0x0020	/* (R/W) D/A clock enable */#define DT2821_HBOE	0x0002	/* (R/W) DIO high byte output enable      */#define DT2821_LBOE	0x0001	/* (R/W) DIO low byte output enable       *//* SUPCSR */#define DT2821_DMAD	0x8000	/* (R)   DMA done                 */#define DT2821_ERRINTEN	0x4000	/* (R/W) interrupt on error               */#define DT2821_CLRDMADNE 0x2000	/* (W)   clear DMA done                   */#define DT2821_DDMA	0x1000	/* (R/W) dual DMA                 */#define DT2821_DS1	0x0800	/* (R/W) DMA select 1                     */#define DT2821_DS0	0x0400	/* (R/W) DMA select 0                     */#define DT2821_BUFFB	0x0200	/* (R/W) buffer B selected                */#define DT2821_SCDN	0x0100	/* (R)   scan done                        */#define DT2821_DACON	0x0080	/* (W)   DAC single conversion            */#define DT2821_ADCINIT	0x0040	/* (W)   A/D initialize                   */#define DT2821_DACINIT	0x0020	/* (W)   D/A initialize                   */#define DT2821_PRLD	0x0010	/* (W)   preload multiplexer              */#define DT2821_STRIG	0x0008	/* (W)   software trigger         */#define DT2821_XTRIG	0x0004	/* (R/W) external trigger enable  */#define DT2821_XCLK	0x0002	/* (R/W) external clock enable            */#define DT2821_BDINIT	0x0001	/* (W)   initialize board         */static comedi_lrange range_dt282x_ai_lo_bipolar = { 4, {	RANGE( -10,	10 ),	RANGE( -5,	5 ),	RANGE( -2.5,	2.5 ),	RANGE( -1.25,	1.25 )}};static comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {	RANGE( 0,	10 ),	RANGE( 0,	5 ),	RANGE( 0,	2.5 ),	RANGE( 0,	1.25 )}};static comedi_lrange range_dt282x_ai_5_bipolar = { 4, {	RANGE( -5,	5 ),	RANGE( -2.5,	2.5 ),	RANGE( -1.25,	1.25 ),	RANGE( -0.625,	0.625 ),}};static comedi_lrange range_dt282x_ai_5_unipolar = { 4, {	RANGE( 0,	5 ),	RANGE( 0,	2.5 ),	RANGE( 0,	1.25 ),	RANGE( 0,	0.625 ),}};static comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {	RANGE( -10,	10 ),	RANGE( -1,	1 ),	RANGE( -0.1,	0.1 ),	RANGE( -0.02,	0.02 )}};static comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {	RANGE( 0,	10 ),	RANGE( 0,	1 ),	RANGE( 0,	0.1 ),	RANGE( 0,	0.02 )}};typedef struct {	char *name;	int adbits;	int adchan_se;	int adchan_di;	int ai_speed;	int ispgl;	int dachan;	int dabits;} boardtype_t;static boardtype_t boardtypes[] ={	{	name:		"dt2821",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		0,		dachan:		2,		dabits:		12,	},	{	name:		"dt2823",		adbits:		16,		adchan_se:	0,		adchan_di:	4,		ai_speed:	4000,		ispgl:		0,		dachan:		2,		dabits:		16,	},	{	name:		"dt2824-pgh",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		0,		dachan:		0,		dabits:		0,	},	{	name:		"dt2824-pgl",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		1,		dachan:		0,		dabits:		0,	},	{	name:		"dt2825",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		0,		dachan:		2,		dabits:		12,	},	{	name:		"dt2827",		adbits:		16,		adchan_se:	0,		adchan_di:	4,		ai_speed:	4000,		ispgl:		0,		dachan:		2,		dabits:		12,	},	{	name:		"dt2828",		adbits:		12,		adchan_se:	4,		adchan_di:	0,		ai_speed:	4000,		ispgl:		0,		dachan:		2,		dabits:		12,	},	{	name:		"dt21-ez",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		0,		dachan:		2,		dabits:		12,	},	{	name:		"dt23-ez",		adbits:		16,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		0,		dachan:		0,		dabits:		0,	},	{	name:		"dt24-ez",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		0,		dachan:		0,		dabits:		0,	},	{	name:		"dt24-ez-pgl",		adbits:		12,		adchan_se:	16,		adchan_di:	8,		ai_speed:	4000,		ispgl:		1,		dachan:		0,		dabits:		0,	},};#define n_boardtypes sizeof(boardtypes)/sizeof(boardtype_t)#define this_board ((boardtype_t *)dev->board_ptr)typedef struct {	int ad_2scomp;		/* we have 2's comp jumper set  */	int da0_2scomp;		/* same, for DAC0               */	int da1_2scomp;		/* same, for DAC1               */	comedi_lrange *darangelist[2];	sampl_t ao[2];	int dacsr;		/* software copies of registers */	int adcsr;	int supcsr;	int ntrig;	int nread;	struct{		int chan;		short *buf;	/* DMA buffer */		int size;	/* size of current transfer */	}dma[2];	int dma_maxsize;	/* max size of DMA transfer (in bytes) */	int usedma;		/* driver uses DMA              */	int current_dma_chan;	int dma_dir;} dt282x_private;#define devpriv ((dt282x_private *)dev->private)#define boardtype (*(boardtype_t *)dev->board_ptr)/* *    Some useless abstractions */#define chan_to_DAC(a)	((a)&1)#define update_dacsr(a)	outw(devpriv->dacsr|(a),dev->iobase+DT2821_DACSR)#define update_adcsr(a)	outw(devpriv->adcsr|(a),dev->iobase+DT2821_ADCSR)#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)#define update_supcsr(a)	outw(devpriv->supcsr|(a),dev->iobase+DT2821_SUPCSR)/* *    danger! macro abuse... a is the expression to wait on, and b is *      the statement(s) to execute if it doesn't happen. */#define wait_for(a,b)	 				\	do{						\		int _i;					\		for(_i=0;_i<DT2821_TIMEOUT;_i++){	\			if(a){_i=0;break;}		\			comedi_udelay(5);			\		}					\		if(_i){b}				\	}while(0)static int dt282x_attach(comedi_device * dev, comedi_devconfig * it);static int dt282x_detach(comedi_device * dev);static comedi_driver driver_dt282x={	driver_name:	"dt282x",	module:		THIS_MODULE,	attach:		dt282x_attach,	detach:		dt282x_detach,	board_name:	boardtypes,	num_names:	n_boardtypes,	offset:		sizeof(boardtype_t),};COMEDI_INITCLEANUP(driver_dt282x);static void free_resources(comedi_device *dev);static int prep_ai_dma(comedi_device * dev,int chan,int size);static int prep_ao_dma(comedi_device * dev,int chan,int size);static int dt282x_ai_cancel(comedi_device * dev, comedi_subdevice * s);static int dt282x_ao_cancel(comedi_device * dev, comedi_subdevice * s);static int dt282x_ns_to_timer(int *nanosec,int round_mode);static int dt282x_grab_dma(comedi_device *dev,int dma1,int dma2);static void dt282x_copy_to_buffer(comedi_device *dev,sampl_t *buf,	unsigned int nbytes){	comedi_async *async = dev->subdevices[0].async;	unsigned int i;	unsigned short mask=(1<<boardtype.adbits)-1;	unsigned short sign=1<<(boardtype.adbits-1);	unsigned short *abuf;	int n;	if(devpriv->ad_2scomp){		sign = 1<<(boardtype.adbits-1);	}else{		sign = 0;	}	abuf = async->prealloc_buf + async->buf_write_ptr;	if(async->buf_write_ptr + nbytes >= async->prealloc_bufsz){		n = (async->prealloc_bufsz - async->buf_write_ptr - nbytes)/2;		for(i=0;i<n;i++){			abuf[i] = (buf[i]&mask)^sign;		}		nbytes -= n;		abuf = async->prealloc_buf;		buf = buf + i;	}	n = nbytes/2;	for(i=0;i<n;i++){		abuf[i] = (buf[i]&mask)^sign;	}}static void dt282x_ao_dma_interrupt(comedi_device * dev){	void *ptr;	int size;	int i;	comedi_subdevice *s=dev->subdevices+1;	update_supcsr(DT2821_CLRDMADNE);	if(!s->async->prealloc_buf){		printk("async->data disappeared.  dang!\n");		return;	}	i=devpriv->current_dma_chan;	ptr=devpriv->dma[i].buf;	disable_dma(devpriv->dma[i].chan);	devpriv->current_dma_chan=1-i;	size = comedi_buf_read_n_available(s->async);	if(size>devpriv->dma_maxsize)size=devpriv->dma_maxsize;	if( size == 0){		rt_printk("dt282x: AO underrun\n");		dt282x_ao_cancel(dev,s);		s->async->events |= COMEDI_CB_OVERFLOW;		comedi_event(dev,s,s->async->events);		return;	}	comedi_buf_memcpy_from(s->async, 0, ptr, size);	comedi_buf_read_free(s->async, size);	prep_ao_dma(dev,i,size);	enable_dma(devpriv->dma[i].chan);	comedi_event(dev,s,s->async->events);	return;}static void dt282x_ai_dma_interrupt(comedi_device * dev){	void *ptr;	int size;	int i;	int ret;	comedi_subdevice *s=dev->subdevices;	update_supcsr(DT2821_CLRDMADNE);	if(!s->async->prealloc_buf){		printk("async->data disappeared.  dang!\n");		return;	}	i = devpriv->current_dma_chan;	ptr = devpriv->dma[i].buf;	size = devpriv->dma[i].size;	disable_dma(devpriv->dma[i].chan);	devpriv->current_dma_chan = 1-i;	ret = comedi_buf_write_alloc(s->async, size);	if(!ret){		rt_printk("dt282x: AI buffer overflow\n");		s->async->events |= COMEDI_CB_OVERFLOW;		comedi_event(dev,s,s->async->events);		return;	}	dt282x_copy_to_buffer(dev, ptr, size);	comedi_buf_write_free(s->async, size);	devpriv->nread-=size/2;	if(devpriv->nread<0){		printk("dt282x: off by one\n");		devpriv->nread=0;	}	if (!devpriv->nread) {		devpriv->adcsr=0;		update_adcsr(0);		/* this eliminates "extra sample" issues */		devpriv->supcsr = 0;		update_supcsr(DT2821_ADCINIT);		s->async->events |= COMEDI_CB_EOA;		comedi_event(dev,s,s->async->events);		return;	}#if 1	/* clear the dual dma flag, making this the last dma segment */	/* XXX probably wrong */	if(!devpriv->ntrig){		devpriv->supcsr &= ~(DT2821_DDMA);		update_supcsr(0);	}#endif	/* restart the channel */	prep_ai_dma(dev,i,0);	enable_dma(devpriv->dma[i].chan);	comedi_event(dev,s,s->async->events);}static int prep_ai_dma(comedi_device * dev,int chan,int n){	int dma_chan;	unsigned long dma_ptr;	unsigned long flags;	if(!devpriv->ntrig)		return 0;	if(n==0)		n = devpriv->dma_maxsize;	if (n >= devpriv->ntrig*2)		n = devpriv->ntrig*2;	devpriv->ntrig -= n/2;	devpriv->dma[chan].size = n;	dma_chan = devpriv->dma[chan].chan;	dma_ptr = virt_to_bus(devpriv->dma[chan].buf);	set_dma_mode(dma_chan, DMA_MODE_READ);	flags=claim_dma_lock();	set_dma_addr(dma_chan, dma_ptr);	set_dma_count(dma_chan, n);	release_dma_lock(flags);	return n;}static int prep_ao_dma(comedi_device * dev,int chan,int n){	int dma_chan;	unsigned long dma_ptr;	unsigned long flags;	devpriv->dma[chan].size = n;	dma_chan = devpriv->dma[chan].chan;	dma_ptr = virt_to_bus(devpriv->dma[chan].buf);	set_dma_mode(dma_chan, DMA_MODE_WRITE);	flags=claim_dma_lock();	set_dma_addr(dma_chan, dma_ptr);	set_dma_count(dma_chan, n );	release_dma_lock(flags);	return n;}static void dt282x_interrupt(int irq, void *d, struct pt_regs *regs){	comedi_device *dev = d;	comedi_subdevice *s = dev->subdevices+0;	comedi_subdevice *s_ao = dev->subdevices+1;	unsigned int supcsr, adcsr, dacsr;	sampl_t data;	int ret;	adcsr=inw(dev->iobase + DT2821_ADCSR);	if (adcsr & DT2821_ADERR) {

⌨️ 快捷键说明

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