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

📄 das800.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    das800.c driver for Keitley das800 series boards and compatibles    Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 2000 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: das800.oDescription: Keithley Metrabyte DAS800 (& compatibles)Author: Frank Mori Hess <fmhess@users.sourceforge.net>Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),  DAS-802 (das-802),  [Measurement Computing] CIO-DAS800 (cio-das800),  CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),  CIO-DAS802/16 (cio-das802/16)Status: works, cio-das802/16 untested - email me if you have tested itConfiguration options:  [0] - I/O port base address  [1] - IRQ (optional, required for timed or externally triggered conversions)Notes:	IRQ can be omitted, although the cmd interface will not work without it.	All entries in the channel/gain list must use the same gain and be	consecutive channels counting upwards in channel number (these are	hardware limitations.)	I've never tested the gain setting stuff since I only have a	DAS-800 board with fixed gain.	The cio-das802/16 does not have a fifo-empty status bit!  Therefore	only fifo-half-full transfers are possible with this card.*//*cmd triggers supported:	start_src:      TRIG_NOW | TRIG_EXT	scan_begin_src: TRIG_FOLLOW	scan_end_src:   TRIG_COUNT	convert_src:    TRIG_TIMER | TRIG_EXT	stop_src:       TRIG_NONE | TRIG_COUNT*/#include <linux/comedidev.h>#include <linux/ioport.h>#include <linux/delay.h>#include "8253.h"#include "comedi_fc.h"#define DAS800_SIZE           8#define TIMER_BASE            1000#define N_CHAN_AI             8	// number of analog input channels/* Registers for the das800 */#define DAS800_LSB            0#define   FIFO_EMPTY            0x1#define   FIFO_OVF              0x2#define DAS800_MSB            1#define DAS800_CONTROL1       2#define   CONTROL1_INTE         0x8#define DAS800_CONV_CONTROL   2#define   ITE                   0x1#define   CASC                  0x2#define   DTEN                  0x4#define   IEOC                  0x8#define   EACS                  0x10#define   CONV_HCEN             0x80#define DAS800_SCAN_LIMITS    2#define DAS800_STATUS         2#define   IRQ                   0x8#define   BUSY                  0x80#define DAS800_GAIN           3#define   CIO_FFOV              0x8	// fifo overflow for cio-das802/16#define   CIO_ENHF              0x90	// interrupt fifo half full for cio-das802/16#define   CONTROL1              0x80#define   CONV_CONTROL          0xa0#define   SCAN_LIMITS           0xc0#define   ID                    0xe0#define DAS800_8254           4#define DAS800_STATUS2        7#define   STATUS2_HCEN          0x80#define   STATUS2_INTE          0X20#define DAS800_ID             7typedef struct das800_board_struct{	char *name;	int ai_speed;	comedi_lrange *ai_range;	int resolution;}das800_board;//analog input rangesstatic comedi_lrange range_das800_ai = {	1,	{		RANGE( -5, 5 ),	}};static comedi_lrange range_das801_ai = {	9,	{		RANGE(-5, 5),		RANGE(-10, 10),		RANGE(0, 10),		RANGE(-0.5, 0.5),		RANGE(0, 1),		RANGE(-0.05, 0.05),		RANGE(0, 0.1),		RANGE(-0.01, 0.01),		RANGE(0, 0.02),	}};static comedi_lrange range_cio_das801_ai = {	9,	{		RANGE(-5, 5),		RANGE(-10, 10),		RANGE(0, 10),		RANGE(-0.5, 0.5),		RANGE(0, 1),		RANGE(-0.05, 0.05),		RANGE(0, 0.1),		RANGE(-0.005, 0.005),		RANGE(0, 0.01),	}};static comedi_lrange range_das802_ai = {	9,	{		RANGE(-5, 5),		RANGE(-10, 10),		RANGE(0, 10),		RANGE(-2.5, 2.5),		RANGE(0, 5),		RANGE(-1.25, 1.25),		RANGE(0, 2.5),		RANGE(-0.625, 0.625),		RANGE(0, 1.25),	}};static comedi_lrange range_das80216_ai = {	8,	{		RANGE(-10, 10),		RANGE(0, 10),		RANGE(-5, 5),		RANGE(0, 5),		RANGE(-2.5, 2.5),		RANGE(0, 2.5),		RANGE(-1.25, 1.25),		RANGE(0, 1.25),	}};enum{das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216};static das800_board das800_boards[] ={	{		name:	"das-800",		ai_speed:	25000,		ai_range:	&range_das800_ai,		resolution:	12,	},	{		name:	"cio-das800",		ai_speed:	20000,		ai_range:	&range_das800_ai,		resolution:	12,	},	{		name:		"das-801",		ai_speed:	25000,		ai_range:	&range_das801_ai,		resolution:	12,	},	{		name:	"cio-das801",		ai_speed:	20000,		ai_range:	&range_cio_das801_ai,		resolution:	12,	},	{		name:		"das-802",		ai_speed:	25000,		ai_range:	&range_das802_ai,		resolution:	12,	},	{		name:	"cio-das802",		ai_speed:	20000,		ai_range:	&range_das802_ai,		resolution:	12,	},	{		name:	"cio-das802/16",		ai_speed:	10000,		ai_range:	&range_das80216_ai,		resolution:	16,	},};/* * Useful for shorthand access to the particular board structure */#define thisboard ((das800_board *)dev->board_ptr)typedef struct{	volatile unsigned int count;  /* number of data points left to be taken */	volatile int forever;  /* flag indicating whether we should take data forever */	unsigned int divisor1;	/* value to load into board's counter 1 for timed conversions */	unsigned int divisor2; 	/* value to load into board's counter 2 for timed conversions */	volatile int do_bits;	/* digital output bits */}das800_private;#define devpriv ((das800_private *)dev->private)static int das800_attach(comedi_device *dev,comedi_devconfig *it);static int das800_detach(comedi_device *dev);static int das800_cancel(comedi_device *dev, comedi_subdevice *s);static comedi_driver driver_das800={	driver_name:	"das800",	module:		THIS_MODULE,	attach:		das800_attach,	detach:		das800_detach,	num_names:	sizeof(das800_boards) / sizeof(das800_board),	board_name:	(char **)das800_boards,	offset:		sizeof(das800_board),};static void das800_interrupt(int irq, void *d, struct pt_regs *regs);static void enable_das800(comedi_device *dev);static void disable_das800(comedi_device *dev);static int das800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd);static int das800_ai_do_cmd(comedi_device *dev, comedi_subdevice *s);static int das800_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int das800_di_rbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int das800_do_wbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int das800_probe(comedi_device *dev);static int das800_set_frequency(comedi_device *dev);/* checks and probes das-800 series board type */static int das800_probe(comedi_device *dev){	int id_bits;	unsigned long irq_flags;	int board;	// 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(ID, dev->iobase + DAS800_GAIN);	/* select base address + 7 to be ID register */	id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	board = thisboard - das800_boards;	switch(id_bits)	{		case 0x0:			if(board == das800)			{				printk(" Board model: DAS-800\n");				return board;			}			if(board == ciodas800)			{				printk(" Board model: CIO-DAS800\n");				return board;			}			printk(" Board model (probed): DAS-800\n");			return das800;			break;		case 0x2:			if(board == das801)			{				printk(" Board model: DAS-801\n");				return board;			}			if(board == ciodas801)			{				printk(" Board model: CIO-DAS801\n");				return board;			}			printk(" Board model (probed): DAS-801\n");			return das801;			break;		case 0x3:			if(board == das802)			{				printk(" Board model: DAS-802\n");				return board;			}			if(board == ciodas802)			{				printk(" Board model: CIO-DAS802\n");				return board;			}			if(board == ciodas80216)			{				printk(" Board model: CIO-DAS802/16\n");				return board;			}			printk(" Board model (probed): DAS-802\n");			return das802;			break;		default :			printk(" Board model: probe returned 0x%x (unknown)\n", id_bits);			return board;			break;	}	return -1;}/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_das800);/* interrupt service routine */static void das800_interrupt(int irq, void *d, struct pt_regs *regs){	short i;		/* loop index */	sampl_t dataPoint = 0;	comedi_device *dev = d;	comedi_subdevice *s = dev->read_subdev;	/* analog input subdevice */	comedi_async *async;	int status;	unsigned long irq_flags;	static const int max_loops = 128;	// half-fifo size for cio-das802/16	// flags	int fifo_empty = 0;	int fifo_overflow = 0;	status = inb(dev->iobase + DAS800_STATUS);	/* if interrupt was not generated by board or driver not attached, quit */	if(!(status & IRQ) || !(dev->attached))	{		return;	}	/* wait until here to initialize async, since we will get null dereference	 * if interrupt occurs before driver is fully attached!	 */	async = s->async;	// if hardware conversions are not enabled, then quit	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select base address + 7 to be STATUS2 register */	status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;	/* don't release spinlock yet since we want to make sure noone else disables hardware conversions */	if(status == 0)	{		comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);		return;	}	/* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */	for(i = 0; i < max_loops; i++)	{		/* read 16 bits from dev->iobase and dev->iobase + 1 */		dataPoint = inb(dev->iobase + DAS800_LSB);		dataPoint += inb(dev->iobase + DAS800_MSB) << 8;		if(thisboard->resolution == 12)		{			fifo_empty = dataPoint & FIFO_EMPTY;			fifo_overflow = dataPoint & FIFO_OVF;			if(fifo_overflow) break;		}else		{			fifo_empty = 0;	// cio-das802/16 has no fifo empty status bit		}		if(fifo_empty)		{			break;		}		/* strip off extraneous bits for 12 bit cards*/		if(thisboard->resolution == 12)			dataPoint = (dataPoint >> 4) & 0xfff;		/* if there are more data points to collect */		if(devpriv->count > 0 || devpriv->forever == 1)		{			/* write data point to buffer */			cfc_write_to_buffer( s, dataPoint);			if(devpriv->count > 0) devpriv->count--;		}	}	async->events |= COMEDI_CB_BLOCK;	/* check for fifo overflow */	if(thisboard->resolution == 12)	{		fifo_overflow = dataPoint & FIFO_OVF;	// else cio-das802/16	}else	{		fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;	}	if(fifo_overflow)	{		comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);		comedi_error(dev, "DAS800 FIFO overflow");		das800_cancel(dev, dev->subdevices + 0);		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;		comedi_event(dev, s, async->events);		async->events = 0;		return;	}	if(devpriv->count > 0 || devpriv->forever == 1)	{		/* Re-enable card's interrupt.		 * We already have spinlock, so indirect addressing is safe */		outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */		outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);	/* otherwise, stop taking data */	} else	{		disable_das800(dev);		/* diable hardware triggered conversions */		async->events |= COMEDI_CB_EOA;	}	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	comedi_event(dev, s, async->events);	async->events = 0;	return;}static int das800_attach(comedi_device *dev, comedi_devconfig *it){	comedi_subdevice *s;	int iobase = it->options[0];

⌨️ 快捷键说明

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