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

📄 pcl818.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*   module/pcl818.c   Author:  Michal Dobes <dobes@tesnet.cz>     hardware driver for Advantech cards:    card:   PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718    driver: pcl818l,  pcl818h,  pcl818hd,  pcl818hg,  pcl818,  pcl718*//*Driver: pcl818.oDescription: Advantech PCL-818 cards, PCL-718Author: Michal Dobes <dobes@tesnet.cz>Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),  PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),  PCL-718 (pcl718)Status: worksAll cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.Differences are only at maximal sample speed, range list and FIFOsupport.The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) supportonly mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFObut this code is untested.A word or two about DMA. Driver support DMA operations at two ways:1) DMA uses two buffers and after one is filled then is generated   INT and DMA restart with second buffer. With this mode I'm unable run   more that 80Ksamples/secs without data dropouts on K6/233.2) DMA uses one buffer and run in autoinit mode and the data are   from DMA buffer moved on the fly with 2kHz interrupts from RTC.   This mode is used if the interrupt 8 is available for allocation.   If not, then first DMA mode is used. With this I can run at   full speed one card (100ksamples/secs) or two cards with   60ksamples/secs each (more is problem on account of ISA limitations).   To use this mode you must have compiled  kernel with disabled   "Enhanced Real Time Clock Support".   Maybe you can have problems if you use xntpd or similar.   If you've data dropouts with DMA mode 2 then:    a) disable IDE DMA    b) switch text mode console to fb.   Options for PCL-818L:    [0] - IO Base    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)    [2] - DMA	(0=disable, 1, 3)    [3] - 0, 10=10MHz clock for 8254              1= 1MHz clock for 8254    [4] - 0,  5=A/D input  -5V.. +5V          1, 10=A/D input -10V..+10V    [5] - 0,  5=D/A output 0-5V  (internal reference -5V)          1, 10=D/A output 0-10V (internal reference -10V)	  2    =D/A output unknow (external reference)          Options for PCL-818, PCL-818H:    [0] - IO Base    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)    [2] - DMA	(0=disable, 1, 3)    [3] - 0, 10=10MHz clock for 8254              1= 1MHz clock for 8254    [4] - 0,  5=D/A output 0-5V  (internal reference -5V)          1, 10=D/A output 0-10V (internal reference -10V)	  2    =D/A output unknow (external reference)   Options for PCL-818HD, PCL-818HG:    [0] - IO Base    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)    [2] - DMA/FIFO  (-1=use FIFO, 0=disable both FIFO and DMA,                       1=use DMA ch 1, 3=use DMA ch 3)    [3] - 0, 10=10MHz clock for 8254              1= 1MHz clock for 8254    [4] - 0,  5=D/A output 0-5V  (internal reference -5V)          1, 10=D/A output 0-10V (internal reference -10V)   	  2    =D/A output unknow (external reference)   Options for PCL-718:    [0] - IO Base    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)    [2] - DMA	(0=disable, 1, 3)    [3] - 0, 10=10MHz clock for 8254              1= 1MHz clock for 8254    [4] -     0=A/D Range is +/-10V	      1=             +/-5V	      2=             +/-2.5V	      3=             +/-1V	      4=             +/-0.5V 	      5=  	     user defined bipolar	      6=	     0-10V	      7=	     0-5V 	      8=	     0-2V	      9=	     0-1V	     10=	     user defined unipolar    [5] - 0,  5=D/A outputs 0-5V  (internal reference -5V)          1, 10=D/A outputs 0-10V (internal reference -10V)	      2=D/A outputs unknow (external reference)    [6] - 0, 60=max  60kHz A/D sampling          1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)*/#include <linux/comedidev.h>#include <linux/ioport.h>#include <linux/mc146818rtc.h>#include <linux/delay.h>#include <asm/dma.h>#include "8253.h"// #define PCL818_MODE13_AO 1// boards constants#define boardPCL818L 0#define boardPCL818H 1#define boardPCL818HD 2#define boardPCL818HG 3#define boardPCL818 4#define boardPCL718 5// IO space len#define PCLx1x_RANGE 16// IO space len if we use FIFO#define PCLx1xFIFO_RANGE 32// W: clear INT request#define PCL818_CLRINT 8// R: return status byte#define PCL818_STATUS 8// R: A/D high byte W: A/D range control#define PCL818_RANGE 1// R: next mux scan channel W: mux scan channel & range control pointer#define PCL818_MUX 2// R/W: operation control register#define PCL818_CONTROL 9// W: counter enable#define PCL818_CNTENABLE 10// R: low byte of A/D W: soft A/D trigger#define PCL818_AD_LO 0// R: high byte of A/D W: A/D range control#define PCL818_AD_HI 1// W: D/A low&high byte#define PCL818_DA_LO 4#define PCL818_DA_HI 5// R: low&high byte of DI #define PCL818_DI_LO 3#define PCL818_DI_HI 11// W: low&high byte of DO#define PCL818_DO_LO 3#define PCL818_DO_HI 11// W: PCL718 second D/A#define PCL718_DA2_LO 6#define PCL718_DA2_HI 7// counters#define PCL818_CTR0 12#define PCL818_CTR1 13#define PCL818_CTR2 14// W: counter control#define PCL818_CTRCTL 15// W: fifo enable/disable#define PCL818_FI_ENABLE 6// W: fifo interrupt clear#define PCL818_FI_INTCLR 20// W: fifo interrupt clear#define PCL818_FI_FLUSH 25// R: fifo status#define PCL818_FI_STATUS 25// R: one record from FIFO#define PCL818_FI_DATALO 23#define PCL818_FI_DATAHI 23// type of interrupt handler#define INT_TYPE_AI1_INT 1#define INT_TYPE_AI1_DMA 2 #define INT_TYPE_AI1_FIFO 3#define INT_TYPE_AI3_INT 4#define INT_TYPE_AI3_DMA 5#define INT_TYPE_AI3_FIFO 6#ifdef PCL818_MODE13_AO#define INT_TYPE_AO1_INT 7#define INT_TYPE_AO3_INT 8#endif#define INT_TYPE_AI1_DMA_RTC 9#define INT_TYPE_AI3_DMA_RTC 10// RTC stuff...#define RTC_IRQ 	8#define RTC_IO_EXTENT	0x10#define MAGIC_DMA_WORD 0x5a5astatic comedi_lrange range_pcl818h_ai = { 9, {	BIP_RANGE(5),	BIP_RANGE(2.5),	BIP_RANGE(1.25),	BIP_RANGE(0.625),	UNI_RANGE(10),	UNI_RANGE(5),	UNI_RANGE(2.5),	UNI_RANGE(1.25),	BIP_RANGE(10),}};static comedi_lrange range_pcl818hg_ai = { 10, {	BIP_RANGE(5),	BIP_RANGE(0.5),	BIP_RANGE(0.05),	BIP_RANGE(0.005),	UNI_RANGE(10),	UNI_RANGE(1),	UNI_RANGE(0.1),	UNI_RANGE(0.01),	BIP_RANGE(10),	BIP_RANGE(1),	BIP_RANGE(0.1),	BIP_RANGE(0.01),}};static comedi_lrange range_pcl818l_l_ai = { 4, {	BIP_RANGE(5),	BIP_RANGE(2.5),	BIP_RANGE(1.25),	BIP_RANGE(0.625),}};static comedi_lrange range_pcl818l_h_ai = { 4, {	BIP_RANGE(10),	BIP_RANGE(5),	BIP_RANGE(2.5),	BIP_RANGE(1.25),}};static comedi_lrange range718_bipolar1 = { 1, { BIP_RANGE(1), }};static comedi_lrange range718_bipolar0_5 = { 1, { BIP_RANGE(0.5), }};static comedi_lrange range718_unipolar2 = { 1, { UNI_RANGE(2), }};static comedi_lrange range718_unipolar1 = { 1, { BIP_RANGE(1), }};static int pcl818_attach(comedi_device *dev,comedi_devconfig *it);static int pcl818_detach(comedi_device *dev);static int RTC_lock = 0;		/* RTC lock */static int RTC_timer_lock = 0;		/* RTC int lock */typedef struct {	char 		*name;		// driver name	int 		n_ranges;	// len of range list	int 		n_aichan_se;	// num of A/D chans in single ended  mode	int 		n_aichan_diff;	// num of A/D chans in diferencial mode	unsigned int 	ns_min;		// minimal alllowed delay between samples (in ns)	int 		n_aochan;	// num of D/A chans	int 		n_dichan;	// num of DI chans	int 		n_dochan;	// num of DO chans	comedi_lrange 	*ai_range_type;	// default A/D rangelist	comedi_lrange 	*ao_range_type;	// dafault D/A rangelist	int 		io_range;	// len of IO space	unsigned int 	IRQbits;	// allowed interrupts	unsigned int 	DMAbits; 	// allowed DMA chans	int 		ai_maxdata;	// maxdata for A/D	int 		ao_maxdata;	// maxdata for D/A           	int 		ai_chanlist;	// allowed len of channel list A/D	int 		ao_chanlist;	// allowed len of channel list D/A	unsigned char 	fifo;		// 1=board has FIFO	int		is_818;} boardtype;static boardtype boardtypes[] ={	{"pcl818l",   4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc, 	  0x0a, 0xfff, 0xfff, 1024, 1, 0, 1 },	{"pcl818h",   9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,   &range_unipolar5, PCLx1x_RANGE, 0x00fc, 	  0x0a, 0xfff, 0xfff, 1024, 1, 0, 1 },	{"pcl818hd",  9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,   &range_unipolar5, PCLx1x_RANGE, 0x00fc, 	  0x0a, 0xfff, 0xfff, 1024, 1, 1, 1 },	{"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,  &range_unipolar5, PCLx1x_RANGE, 0x00fc,	  0x0a, 0xfff, 0xfff, 1024, 1, 1, 1 },	{"pcl818",    9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,   &range_unipolar5, PCLx1x_RANGE, 0x00fc, 	  0x0a, 0xfff, 0xfff, 1024, 2, 0, 1 },	{"pcl718",    1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,    &range_unipolar5, PCLx1x_RANGE, 0x00fc, 	  0x0a, 0xfff, 0xfff, 1024, 2, 0, 0 },	/* pcm3718 */	{"pcm3718",   9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,   &range_unipolar5, PCLx1x_RANGE, 0x00fc, 	  0x0a, 0xfff, 0xfff, 1024, 0, 0, 1 /* XXX ? */ },};#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))static comedi_driver driver_pcl818={	driver_name:	"pcl818",	module:		THIS_MODULE,	attach:		pcl818_attach,	detach:		pcl818_detach,	board_name:	boardtypes,	num_names:	n_boardtypes,	offset:		sizeof(boardtype),};COMEDI_INITCLEANUP(driver_pcl818);typedef struct {	int 		dma;		// used DMA, 0=don't use DMA	int 		dma_rtc;	// 1=RTC used with DMA, 0=no RTC alloc	int		io_range;	unsigned int 	rtc_iobase;	// RTC port region	unsigned int 	rtc_iosize;	unsigned int 	rtc_irq;	unsigned long 	dmabuf[2];	// pointers to begin of DMA buffers	unsigned int 	dmapages[2];	// len of DMA buffers in PAGE_SIZEs	unsigned int 	hwdmaptr[2];	// hardware address of DMA buffers	unsigned int 	hwdmasize[2]; 	// len of DMA buffers in Bytes	unsigned int 	dmasamplsize;	// size in samples hwdmasize[0]/2	unsigned int 	last_top_dma; 	// DMA pointer in last RTC int	int 		next_dma_buf;	// which DMA buffer will be used next round	long 		dma_runs_to_end;// how many we must permorm DMA transfer to end of record	unsigned long 	last_dma_run;	// how many bytes we must transfer on last DMA page	unsigned char 	neverending_ai;	// if=1, then we do neverending record (you must use cancel())	unsigned int 	ns_min;		// manimal alllowed delay between samples (in us) for actual card	int 		i8253_osc_base;	// 1/frequency of on board oscilator in ns	int 		irq_free;	// 1=have allocated IRQ	int 		irq_blocked;	// 1=IRQ now uses any subdev	int 		rtc_irq_blocked;// 1=we now do AI with DMA&RTC	int 		irq_was_now_closed;// when IRQ finish, there's stored int818_mode for last interrupt	int 		int818_mode; 	// who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma 	comedi_subdevice *last_int_sub;	// ptr to subdevice which now finish	int 		int13_act_scan;	// how many scans we finished	int 		int13_act_chan;	// actual position in actual scan	unsigned int 	act_chanlist[16];// MUX setting for actual AI operations	unsigned int 	act_chanlist_len;// how long is actual MUX list	unsigned int 	act_chanlist_pos;// actual position in MUX list	comedi_subdevice *sub_ai;	// ptr to AI subdevice	unsigned char 	usefifo;	// 1=use fifo	struct timer_list rtc_irq_timer;// timer for RTC sanity check	unsigned long 	rtc_freq;	// RTC int freq	lsampl_t	ao_readback[2];} pcl818_private;static unsigned int muxonechan[] ={ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // used for gain list programming                                    0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};#define devpriv ((pcl818_private *)dev->private)#define this_board ((boardtype *)dev->board_ptr)/* ==============================================================================*/#ifdef unusedstatic int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, comedi_trig * it);#endifstatic int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s);#ifdef unusedstatic void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);#endifstatic int set_rtc_irq_bit(unsigned char bit);#ifdef unusedstatic void rtc_dropped_irq(unsigned long data);static int rtc_setfreq_irq(int freq);#endif/* ==============================================================================   ANALOG INPUT MODE0, 818 cards, slow version*/static int pcl818_ai_insn_read(comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data){	int n;        int timeout; 	/* software trigger, DMA and INT off */       	outb(0, dev->iobase+PCL818_CONTROL);	/* select channel */       	outb(muxonechan[CR_CHAN(insn->chanspec)],		dev->iobase+PCL818_MUX);	/* select gain */       	outb(CR_RANGE(insn->chanspec),		dev->iobase+PCL818_RANGE);	for(n=0;n<insn->n;n++){		/* clear INT (conversion end) flag */        	outb(0, dev->iobase+PCL818_CLRINT);		/* start conversion */		outb(0, dev->iobase+PCL818_AD_LO);        	timeout=100;        	while (timeout--) {			if (inb(dev->iobase + PCL818_STATUS) & 0x10)				goto conv_finish;			comedi_udelay(1);        	}        	comedi_error(dev,"A/D insn timeout");		/* clear INT (conversion end) flag */        	outb(0, dev->iobase+PCL818_CLRINT);        	return -EIO;conv_finish:	        data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |			(inb(dev->iobase + PCL818_AD_LO) >> 4));	}	return n;}/* 

⌨️ 快捷键说明

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