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

📄 ni_atmio.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
字号:
/*    comedi/drivers/ni_atmio.c    Hardware driver for NI AT-MIO E series cards    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1997-2001 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: ni_atmio.oDescription: National Instruments AT-MIO-E seriesAuthor: dsDevices: [National Instruments] AT-MIO-16E-1 (ni_atmio),  AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3,  AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10Status: worksUpdated: Thu May  1 20:03:02 CDT 2003The driver now has (2.4) kernel isapnp support, andwill automatically probe for a supported board if theI/O base is left unspecified with comedi_config.However, many ofthe isapnp id numbers are unknown.  If your board is notrecognized, please send the output of 'cat /proc/isapnp'(you may need to modprobe the isa-pnp module for/proc/isapnp to exist) so theid numbers for your board can be added to the driver.Otherwise, you can use the isapnptools package to configureyour board.  Use isapnp toconfigure the I/O base and IRQ for the board, and then passthe same values asparameters in comedi_config.  A sample isapnp.conf file is includedin the etc/ directory of Comedilib.Comedilib includes a utility to autocalibrate these boards.  Theboards seem to boot into a state where the all calibration DACsare at one extreme of their range, thus the default calibrationis terrible.  Calibration at boot is strongly encouraged.To use the extended digital I/O on some of the boards, enable the8255 driver when configuring the Comedi source tree.External triggering is supported for some events.  The channel index(scan_begin_arg, etc.) maps to PFI0 - PFI9.Some of the more esoteric triggering possibilities of these boardsare not supported.*//*	The real guts of the driver is in ni_mio_common.c, which is included	both here and in ni_pcimio.c	Interrupt support added by Truxton Fulton <trux@truxton.com>	References for specifications:	   340747b.pdf  Register Level Programmer Manual (obsolete)	   340747c.pdf  Register Level Programmer Manual (new)	   DAQ-STC reference manual	Other possibly relevant info:	   320517c.pdf  User manual (obsolete)	   320517f.pdf  User manual (new)	   320889a.pdf  delete	   320906c.pdf  maximum signal ratings	   321066a.pdf  about 16x	   321791a.pdf  discontinuation of at-mio-16e-10 rev. c	   321808a.pdf  about at-mio-16e-10 rev P	   321837a.pdf  discontinuation of at-mio-16de-10 rev d	   321838a.pdf  about at-mio-16de-10 rev N	ISSUES:	need to deal with external reference for DAC, and other DAC	properties in board properties	deal with at-mio-16de-10 revision D to N changes, etc.*/#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/isapnp.h>#include "ni_stc.h"#include "8255.h"#undef DEBUG#define ATMIO 1#undef PCIMIO/* *  AT specific setup */#define NI_SIZE 0x20#define MAX_N_CALDACS 32static ni_board ni_boards[]={	{	device_id:	44,		isapnp_id:	0x0000,	/* XXX unknown */		name:		"at-mio-16e-1",		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	8192,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	800,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	2048,		ao_unipolar:	1,		has_8255:	0,		caldac:		{mb88341},	},	{	device_id:	25,		isapnp_id:	0x1900,		name:		"at-mio-16e-2",		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	2048,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	2000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	2048,		ao_unipolar:	1,		has_8255:	0,		caldac:		{mb88341},	},	{	device_id:	36,		isapnp_id:	0x2400,		name:		"at-mio-16e-10",		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	512,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	10000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	0,		ao_unipolar:	1,		caldac:		{mb88341},		has_8255:	0,	},	{	device_id:	37,		isapnp_id:	0x0000,	/* XXX unknown */		name:		"at-mio-16de-10",		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	512,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	10000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	0,		ao_unipolar:	1,		caldac:		{mb88341},		has_8255:	1,	},	{	device_id:	38,		isapnp_id:	0x0000,	/* XXX unknown */		name:		"at-mio-64e-3",		n_adchan:	64,		adbits:		12,		ai_fifo_depth:	2048,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	2000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	2048,		ao_unipolar:	1,		has_8255:	0,		caldac:		{mb88341},	},	{	device_id:	39,		isapnp_id:	0x2700,		name:		"at-mio-16xe-50",		n_adchan:	16,		adbits:		16,		ai_fifo_depth:	512,		alwaysdither:	1,		gainlkup:	ai_gain_8,		ai_speed:	50000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	0,		ao_unipolar:	0,		caldac:		{dac8800,dac8043},		has_8255:	0,	},	{	device_id:	50,		isapnp_id:	0x0000,	/* XXX unknown */		name:		"at-mio-16xe-10",		n_adchan:	16,		adbits:		16,		ai_fifo_depth:	512,		alwaysdither:	1,		gainlkup:	ai_gain_14,		ai_speed:	10000,		n_aochan:	2,		aobits:		16,		ao_fifo_depth:	2048,		ao_unipolar:	1,		caldac:		{dac8800,dac8043,ad8522},		has_8255:	0,	},	{	device_id:	51,		isapnp_id:	0x0000,	/* XXX unknown */		name:		"at-ai-16xe-10",		n_adchan:	16,		adbits:		16,		ai_fifo_depth:	512,		alwaysdither:	1,	/* unknown */		gainlkup:	ai_gain_14,		ai_speed:	10000,		n_aochan:	0,		aobits:		0,		ao_fifo_depth:	0,		aorangelkup:	0,		ao_unipolar:	0,		caldac:		{dac8800,dac8043,ad8522},		has_8255:	0,	}};static int ni_irqpin[]={-1,-1,-1,0,1,2,-1,3,-1,-1,4,5,6,-1,-1,7};#define interrupt_pin(a)	(ni_irqpin[(a)])#define IRQ_POLARITY 0#define NI_E_IRQ_FLAGS		0/* How we access registers */#define ni_writel(a,b)		(outl((a),(b)+dev->iobase))#define ni_readl(a)		(inl((a)+dev->iobase))#define ni_writew(a,b)		(outw((a),(b)+dev->iobase))#define ni_readw(a)		(inw((a)+dev->iobase))#define ni_writeb(a,b)		(outb((a),(b)+dev->iobase))#define ni_readb(a)		(inb((a)+dev->iobase))/* How we access windowed registers *//* We automatically take advantage of STC registers that can be * read/written directly in the I/O space of the board.  The * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */#define win_out(data,addr) __win_out(dev,data,addr)static inline void __win_out(comedi_device *dev, unsigned short data, int addr){	unsigned long flags;	comedi_spin_lock_irqsave(&dev->spinlock,flags);	if((addr)<8){		ni_writew(data,addr*2);	}else{		ni_writew(addr,Window_Address);		ni_writew(data,Window_Data);	}	comedi_spin_unlock_irqrestore(&dev->spinlock,flags);}#define win_out2(data,addr) do{ \	win_out((data)>>16, (addr)); \	win_out((data)&0xffff, (addr)+1); \}while(0)#define win_in(addr) __win_in(dev,addr)static inline unsigned short __win_in(comedi_device *dev, int addr){	unsigned long flags;	int ret;	comedi_spin_lock_irqsave(&dev->spinlock,flags);	if(addr<8){		ret = ni_readw(addr*2);	}else{		ni_writew(addr,Window_Address);		ret = ni_readw(Window_Data);	}	comedi_spin_unlock_irqrestore(&dev->spinlock,flags);	return ret;}#define ao_win_out(a,b) do{ \	ni_writew((b),AO_Window_Address_671x); \	ni_writew((a),AO_Window_Data_671x); \}while(0)#ifdef __ISAPNP__static struct isapnp_device_id device_ids[] = {	{ ISAPNP_DEVICE_SINGLE('N','I','C',0x1900,'N','I','C',0x0000), },	{ ISAPNP_DEVICE_SINGLE('N','I','C',0x2400,'N','I','C',0x2400), },	{ ISAPNP_DEVICE_SINGLE('N','I','C',0x2700,'N','I','C',0x2700), },	{ ISAPNP_DEVICE_SINGLE_END, },};MODULE_DEVICE_TABLE(isapnp, device_ids);#endiftypedef struct{	struct pci_dev *isapnp_dev;	NI_PRIVATE_COMMON}ni_private;#define devpriv ((ni_private *)dev->private)static int ni_atmio_attach(comedi_device *dev,comedi_devconfig *it);static int ni_atmio_detach(comedi_device *dev);static comedi_driver driver_atmio={	driver_name:	"ni_atmio",	module:		THIS_MODULE,	attach:		ni_atmio_attach,	detach:		ni_atmio_detach,};COMEDI_INITCLEANUP(driver_atmio);#include "ni_mio_common.c"static int ni_getboardtype(comedi_device *dev);/* clean up allocated resources */static int ni_atmio_detach(comedi_device *dev){	mio_common_detach(dev);	if(dev->iobase)		release_region(dev->iobase,NI_SIZE);	if(dev->irq){		comedi_free_irq(dev->irq,dev);	}#ifdef __ISAPNP__	if(devpriv->isapnp_dev)		devpriv->isapnp_dev->deactivate(devpriv->isapnp_dev);#endif	return 0;}static int ni_isapnp_find_board( struct pci_dev **dev ){#ifdef __ISAPNP__	struct pci_dev *isapnp_dev = NULL;	int i;		for( i = 0; i < n_ni_boards; i++ )	{		isapnp_dev = isapnp_find_dev(NULL,			ISAPNP_VENDOR('N','I','C'),			ISAPNP_FUNCTION( ni_boards[ i ].isapnp_id ),			NULL);		if(!isapnp_dev) continue;		if(isapnp_dev->active)		{			printk( "%s found but already active, skipping.\n", ni_boards[ i ].name );			continue;		}		if(isapnp_dev->prepare(isapnp_dev)<0)			return -EAGAIN;		if(!(isapnp_dev->resource[0].flags & IORESOURCE_IO))			return -ENODEV;#if 0		if(!isapnp_dev->ro){			/* override resource */			if(it->options[0] != 0){				isapnp_resource_change(&isapnp_dev->resource[0],					it->options[0], NI_SIZE);			}		}#endif		if(isapnp_dev->activate(isapnp_dev)<0){			printk("isapnp configure failed!\n");			return -ENOMEM;		}		break;	}	if( i == n_ni_boards ) return -ENODEV;	*dev = isapnp_dev;	return 0;#else	return -EIO;#endif}static int ni_atmio_attach(comedi_device *dev,comedi_devconfig *it){	struct pci_dev *isapnp_dev;	int		ret;	int		iobase;	int		board;	int		irq;	/* allocate private area */	if((ret = alloc_private(dev, sizeof(ni_private))) < 0)		return ret;	iobase=it->options[0];	irq=it->options[1];	isapnp_dev = NULL;	if( iobase == 0 )	{		ret = ni_isapnp_find_board( &isapnp_dev );		if( ret < 0 ) return ret;#ifdef __ISAPNP__		iobase = isapnp_dev->resource[0].start;		irq = isapnp_dev->irq_resource[0].start;		devpriv->isapnp_dev = isapnp_dev;#else		return -EIO;#endif	}	/* reserve our I/O region */	printk("comedi%d: ni_atmio: 0x%04x",dev->minor,iobase);	if(check_region(iobase,NI_SIZE)<0){		printk(" I/O port conflict\n");		return -EIO;	}	request_region(iobase,NI_SIZE,"ni_atmio");	dev->iobase=iobase;#ifdef DEBUG	/* board existence sanity check */       {               int i;               printk(" board fingerprint:");              for(i=0;i<16;i+=2){                       printk(" %04x %02x",inw(dev->iobase+i),inb(dev->iobase+i+1));               }       }#endif	/* get board type */	board=ni_getboardtype(dev);	if(board<0)return -EIO;	dev->board_ptr=ni_boards + board;	printk(" %s",boardtype.name);	dev->board_name=boardtype.name;	/* irq stuff */	if(irq!=0){		if(irq<0 || irq>15 || ni_irqpin[irq]==-1){			printk(" invalid irq\n");			return -EINVAL;		}		printk(" ( irq = %d )",irq);		if( (ret=comedi_request_irq(irq,ni_E_interrupt,NI_E_IRQ_FLAGS,"ni_atmio",dev))<0 ){			printk(" irq not available\n");			return -EINVAL;		}		dev->irq=irq;	}	/* generic E series stuff in ni_mio_common.c */	if( (ret=ni_E_init(dev,it))<0 ){		return ret;	}	return 0;}static int ni_getboardtype(comedi_device *dev){	int device_id=ni_read_eeprom(dev,511);	int i;	for(i=0;i<n_ni_boards;i++){		if(ni_boards[i].device_id==device_id){			return i;		}	}	if(device_id==255){		printk(" can't find board\n");	}else if(device_id == 0){		printk(" EEPROM read error (?) or device not found\n");	}else{		printk(" unknown device ID %d -- contact author\n",device_id);	}	return -1;}

⌨️ 快捷键说明

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