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

📄 ni_mio_cs.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
字号:
/*    comedi/drivers/ni_mio_cs.c    Hardware driver for NI PCMCIA MIO E series cards    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1997-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: ni_mio_cs.oDescription: National Instruments DAQCard E seriesAuthor: dsStatus: worksDevices: [National Instruments] DAQCard-AI-16XE-50 (ni_mio_cs),  DAQCard-AI-16E-4, DAQCard-6062E, DAQCard-6024EUpdated: Thu, 07 Nov 2002 21:09:40 -0800See the notes in the ni_atmio.o driver.*//*	The real guts of the driver is in ni_mio_common.c, which is	included by all the E series drivers.	References for specifications:		   341080a.pdf  DAQCard E Series Register Level Programmer Manual	*/#include <linux/comedidev.h>#include <linux/delay.h>#include "ni_stc.h"#include "8255.h"#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/ds.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:	0x010d,		name:		"DAQCard-ai-16xe-50",		n_adchan:	16,		adbits:		16,		ai_fifo_depth:	1024,		alwaysdither:	0,		gainlkup:	ai_gain_8,		ai_speed:	5000,		n_aochan:	0,		aobits:		0,		ao_fifo_depth:	0,		ao_unipolar:	0,		has_8255:	0,		caldac:		{dac8800,dac8043},	},	{	device_id:	0x010c,		name:		"DAQCard-ai-16e-4",		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	1024,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	4000,		n_aochan:	0,		aobits:		0,		ao_fifo_depth:	0,		ao_unipolar:	0,		has_8255:	0,		caldac:		{mb88341}, /* verified */	},	{	device_id:	0x02c4,		name:		"DAQCard-6062E",		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	1024,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	2000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	2048,		ao_unipolar:	0,		has_8255:	0,		caldac:		{ad8804},	/* verified */	},	{	device_id:	0x075e,		name:		"DAQCard-6024E", /* specs incorrect! */		n_adchan:	16,		adbits:		12,		ai_fifo_depth:	1024,		alwaysdither:	0,		gainlkup:	ai_gain_16,		ai_speed:	5000,		n_aochan:	2,		aobits:		12,		ao_fifo_depth:	0,		ao_unipolar:	0,		has_8255:	0,		caldac:		{dac8800,dac8043},	},	{	device_id:	0x0245,		name:		"DAQCard-6036E", /* specs incorrect! */		n_adchan:	16,		adbits:		16,		ai_fifo_depth:	1024,		alwaysdither:	1,		gainlkup:	ai_gain_4,		ai_speed:	5000,		n_aochan:	2,		aobits:		16,		ao_fifo_depth:	0,		ao_unipolar:	0,		has_8255:	0,		caldac:		{dac8800,dac8043},	},#if 0	{	device_id:	0x0000, /* unknown */		name:		"DAQCard-6715",		n_adchan:	0,		n_aochan:	8,		aobits:		12,		ao_671x:	8192,		caldac:		{mb88341,mb88341},	},#endif};#define interrupt_pin(a)	0#define IRQ_POLARITY 1#define NI_E_IRQ_FLAGS		SA_SHIRQ/* 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 * DAQCard 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)typedef struct{	dev_link_t *link;	NI_PRIVATE_COMMON}ni_private;#define devpriv ((ni_private *)dev->private)static int mio_cs_attach(comedi_device *dev,comedi_devconfig *it);static int mio_cs_detach(comedi_device *dev);static comedi_driver driver_ni_mio_cs={	driver_name:	"ni_mio_cs",	module:		THIS_MODULE,	attach:		mio_cs_attach,	detach:		mio_cs_detach,};#include "ni_mio_common.c"static int ni_getboardtype(comedi_device *dev,dev_link_t *link);/* clean up allocated resources *//* called when driver is removed */static int mio_cs_detach(comedi_device *dev){	mio_common_detach(dev);	/* PCMCIA layer frees the IO region */	if(dev->irq){		comedi_free_irq(dev->irq,dev);	}	return 0;}static void mio_cs_config(dev_link_t *link);static void cs_release(u_long arg);static void cs_detach(dev_link_t *);static int irq_mask;static dev_link_t *dev_list = NULL;static dev_info_t dev_info = "ni_mio_cs";static dev_node_t dev_node = {	"ni_mio_cs",	COMEDI_MAJOR,0,	NULL};static int mio_cs_event(event_t event, int priority, event_callback_args_t *args);static void cs_error(client_handle_t handle, int func, int ret){	error_info_t err = { func, ret };	DPRINTK("cs_error(handle=%p, func=%d, ret=%d)\n",handle,func,ret);	CardServices(ReportError, handle, &err);}static dev_link_t *cs_attach(void){	dev_link_t *link;	client_reg_t client_reg;	int ret;	link=kmalloc(sizeof(*link),GFP_KERNEL);	if(!link)return NULL;	memset(link,0,sizeof(*link));	link->release.function = &cs_release;	link->release.data = (u_long)link;		link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;	link->io.NumPorts1 = 16;	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;	link->irq.IRQInfo2 = irq_mask;	link->conf.Attributes = CONF_ENABLE_IRQ;	link->conf.Vcc = 50;	link->conf.IntType = INT_MEMORY_AND_IO;		link->next = dev_list;	dev_list = link;	client_reg.dev_info = &dev_info;	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;	client_reg.EventMask =		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;	client_reg.event_handler = &mio_cs_event;	client_reg.Version = 0x0210;	client_reg.event_callback_args.client_data = link;	ret = CardServices(RegisterClient, &link->handle, &client_reg);	if (ret != CS_SUCCESS) {		cs_error(link->handle, RegisterClient, ret);		printk("detaching...\n");		cs_detach(link);		return NULL;	}	return link;}static void cs_release(u_long arg){	dev_link_t *link=(void *)arg;	CardServices(ReleaseConfiguration, link->handle);	CardServices(ReleaseIO, link->handle, &link->io);	CardServices(ReleaseIRQ, link->handle, &link->irq);	link->state &= ~DEV_CONFIG;}static void cs_detach(dev_link_t *link){	dev_link_t **linkp;		DPRINTK("cs_detach(link=%p)\n",link);		for(linkp = &dev_list; *linkp; linkp = &(*linkp)->next)		if (*linkp == link) break;	if (*linkp==NULL)		return;	//save_flags	//cli	if (link->state & DEV_RELEASE_PENDING){		printk("dev release pending bug\n");		del_timer(&link->release);		link->state &= ~DEV_RELEASE_PENDING;	}	//restore_flags	if(link->state & DEV_CONFIG) {		cs_release((u_long)link);		if(link->state & DEV_STALE_CONFIG) {			link->state |= DEV_STALE_LINK;			return;		}	}	if(link->handle){		CardServices(DeregisterClient, link->handle);	}}static int mio_cs_event(event_t event, int priority, event_callback_args_t *args){	dev_link_t *link = args->client_data;	DPRINTK("mio_cs_event(event=%x,priority=%d,args=%p)\n",event,priority,args);	switch(event){	case CS_EVENT_CARD_REMOVAL:		DPRINTK("removal event\n");		link->state &= ~DEV_PRESENT;		if(link->state & DEV_CONFIG) {			link->release.expires = jiffies+HZ/20;			link->state |= DEV_RELEASE_PENDING;			add_timer(&link->release);		}		/* XXX disable irq here, to get rid of spurious interrupts */		break;	case CS_EVENT_CARD_INSERTION:		DPRINTK("card insertion event\n");		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;		mio_cs_config(link);		break;	case CS_EVENT_PM_SUSPEND:		DPRINTK("pm suspend event\n");		link->state |= DEV_SUSPEND;		/* fall through */	case CS_EVENT_RESET_PHYSICAL:		DPRINTK("reset physical event\n");		if(link->state & DEV_CONFIG)			CardServices(ReleaseConfiguration, link->handle);		break;	case CS_EVENT_PM_RESUME:		DPRINTK("pm resume event\n");		link->state &= ~DEV_SUSPEND;		/* fall through */	case CS_EVENT_CARD_RESET:		DPRINTK("card reset event\n");		if(DEV_OK(link))			CardServices(RequestConfiguration, link->handle, &link->conf);		break;	default:		DPRINTK("unknown event (ignored)\n");	}	return 0;}static void mio_cs_config(dev_link_t *link){	client_handle_t handle = link->handle;	tuple_t tuple;	u_short buf[128];	cisparse_t parse;	int manfid = 0, prodid = 0;	int ret;	config_info_t conf;	DPRINTK("mio_cs_config(link=%p)\n",link);	tuple.TupleData = (cisdata_t *)buf;	tuple.TupleOffset = 0;	tuple.TupleDataMax = 255;	tuple.Attributes = 0;		tuple.DesiredTuple = CISTPL_CONFIG;	ret=CardServices(GetFirstTuple, handle, &tuple);	ret=CardServices(GetTupleData, handle, &tuple);	ret=CardServices(ParseTuple, handle, &tuple, &parse);	link->conf.ConfigBase = parse.config.base;	link->conf.Present = parse.config.rmask[0];	link->state |= DEV_CONFIG;	CardServices(GetConfigurationInfo,handle,&conf);	link->conf.Vcc=conf.Vcc;#if 0	tuple.DesiredTuple = CISTPL_LONGLINK_MFC;	tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;	info->multi (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);#endif	tuple.DesiredTuple = CISTPL_MANFID;	tuple.Attributes = TUPLE_RETURN_COMMON;	if((CardServices(GetFirstTuple,handle, &tuple) == CS_SUCCESS) &&	   (CardServices(GetTupleData,handle,&tuple) == CS_SUCCESS)){		manfid = le16_to_cpu(buf[0]);		prodid = le16_to_cpu(buf[1]);	}	//printk("manfid = 0x%04x, 0x%04x\n",manfid,prodid);	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;	tuple.Attributes = 0;	ret=CardServices(GetFirstTuple, handle, &tuple);	ret=CardServices(GetTupleData, handle, &tuple);	ret=CardServices(ParseTuple, handle, &tuple, &parse);#if 0	printk(" index: 0x%x\n",parse.cftable_entry.index);	printk(" flags: 0x%x\n",parse.cftable_entry.flags);	printk(" io flags: 0x%x\n",parse.cftable_entry.io.flags);	printk(" io nwin: 0x%x\n",parse.cftable_entry.io.nwin);	printk(" io base: 0x%x\n",parse.cftable_entry.io.win[0].base);	printk(" io len: 0x%x\n",parse.cftable_entry.io.win[0].len);	printk(" irq1: 0x%x\n",parse.cftable_entry.irq.IRQInfo1);	printk(" irq2: 0x%x\n",parse.cftable_entry.irq.IRQInfo2);	printk(" mem flags: 0x%x\n",parse.cftable_entry.mem.flags);	printk(" mem nwin: 0x%x\n",parse.cftable_entry.mem.nwin);	printk(" subtuples: 0x%x\n",parse.cftable_entry.subtuples);#endif#if 0	link->io.NumPorts1=0x20;	link->io.IOAddrLines=5;	link->io.Attributes1=IO_DATA_PATH_WIDTH_AUTO;#endif	link->io.NumPorts1=parse.cftable_entry.io.win[0].len;	link->io.IOAddrLines=parse.cftable_entry.io.flags & CISTPL_IO_LINES_MASK;	link->io.NumPorts2=0;	{		int base;		for(base=0x000;base<0x400;base+=0x20){			link->io.BasePort1=base;			ret=CardServices(RequestIO, handle, &link->io);			//printk("RequestIO 0x%02x\n",ret);			if(!ret)break;		}	}	link->irq.IRQInfo1=parse.cftable_entry.irq.IRQInfo1;	link->irq.IRQInfo2=parse.cftable_entry.irq.IRQInfo2;	ret=CardServices(RequestIRQ, handle, &link->irq);	//printk("RequestIRQ 0x%02x\n",ret);	link->conf.ConfigIndex=1;	ret=CardServices(RequestConfiguration, handle, &link->conf);	//printk("RequestConfiguration %d\n",ret);	link->dev = &dev_node;	link->state &= ~DEV_CONFIG_PENDING;}static int mio_cs_attach(comedi_device *dev,comedi_devconfig *it){	dev_link_t *link;	int ret;		DPRINTK("mio_cs_attach(dev=%p,it=%p)\n",dev,it);	link = dev_list; /* XXX hack */	if(!link)return -EIO;	dev->driver=&driver_ni_mio_cs;	dev->iobase=link->io.BasePort1;	dev->irq=link->irq.AssignedIRQ;	printk("comedi%d: %s: DAQCard: io 0x%04x, irq %d, ",		dev->minor,dev->driver->driver_name,dev->iobase,		dev->irq);#if 0	{		int i;		printk(" board fingerprint:");		for(i=0;i<32;i+=2){		printk(" %04x %02x",inw(dev->iobase+i),inb(dev->iobase+i+1));		}		printk("\n");		printk(" board fingerprint (windowed):");		for(i=0;i<10;i++){			printk(" 0x%04x",win_in(i));		}		printk("\n");	}#endif	dev->board_ptr = ni_boards + ni_getboardtype(dev,link);		printk(" %s",boardtype.name);	dev->board_name=boardtype.name;	if( (ret=comedi_request_irq(dev->irq,ni_E_interrupt,NI_E_IRQ_FLAGS,"ni_mio_cs",dev))<0 ){		printk(" irq not available\n");		return -EINVAL;	}		/* allocate private area */	if((ret=alloc_private(dev,sizeof(ni_private)))<0)		return ret;		if( (ret=ni_E_init(dev,it))<0 ){		return ret;	}	return 0;}static int get_prodid(comedi_device *dev,dev_link_t *link){	client_handle_t handle = link->handle;	tuple_t tuple;	u_short buf[128];	int prodid = 0;	tuple.TupleData = (cisdata_t *)buf;	tuple.TupleOffset = 0;	tuple.TupleDataMax = 255;	tuple.DesiredTuple = CISTPL_MANFID;	tuple.Attributes = TUPLE_RETURN_COMMON;	if((CardServices(GetFirstTuple,handle, &tuple) == CS_SUCCESS) &&	   (CardServices(GetTupleData,handle,&tuple) == CS_SUCCESS)){		prodid = le16_to_cpu(buf[1]);	}		return prodid;}static int ni_getboardtype(comedi_device *dev,dev_link_t *link){	int id;	int i;		id = get_prodid(dev,link);	for(i=0;i<n_ni_boards;i++){		if(ni_boards[i].device_id==id){			return i;		}	}	printk("unknown board 0x%04x -- pretend it is a ",id);	return 0;}#ifdef MODULEint init_module(void){	servinfo_t serv;	CardServices(GetCardServicesInfo, &serv);	if(serv.Revision != CS_RELEASE_CODE){		printk(KERN_NOTICE "mio_cs: Card Services release "			"does not match!\n");		//return -EPERM; /* XXX what to return? */	}	register_pccard_driver(&dev_info, &cs_attach, &cs_detach);	comedi_driver_register(&driver_ni_mio_cs);	return 0;}void cleanup_module(void){	unregister_pccard_driver(&dev_info);#if 0	while(dev_list != NULL)		cs_detach(dev_list);#endif	comedi_driver_unregister(&driver_ni_mio_cs);}#endif

⌨️ 快捷键说明

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