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

📄 amplc_pci230.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 /*    comedi/drivers/amplc_pci230.c    Driver for Amplicon PCI230 and PCI260 Multifunction I/O boards.    Copyright (C) 2001 Allan Willcox <allanwillcox@ozemail.com.au>    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: amplc_pci230.oDescription: Driver for Amplicom PCI230 and PCI260 Multifunction I/O boardsAuthor: Allan Willcox <allanwillcox@ozemail.com.au>Updated: Mon,  3 Sep 2001 17:37:12 -0700Devices: [Amplicon] PCI230 (amplc_pci230), PCI260Status: unknown*/#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/pci.h>#include "8253.h"#include "8255.h"/* PCI230 PCI configuration register information */#define PCI_VENDOR_ID_AMPLICON 0x14dc#define PCI_DEVICE_ID_PCI230 0x0000#define PCI_DEVICE_ID_PCI260 0x0006#define PCI230_IO1_SIZE 32		/* Size of I/O space 1 */#define PCI230_IO2_SIZE 16		/* Size of I/O space 2 *//* PCI230 i/o space 1 registers. */#define PCI230_PPI_X_A   0x00   /* User PPI port A */#define PCI230_PPI_X_B   0x01   /* User PPI port B */#define PCI230_PPI_X_C   0x02   /* User PPI port C */#define PCI230_PPI_X_CMD 0x03   /* User PPI control word */#define PCI230_Z2_CT0    0x14   /* 82C54 counter/timer 0 */#define PCI230_Z2_CT1    0x15   /* 82C54 counter/timer 1 */#define PCI230_Z2_CT2    0x16   /* 82C54 counter/timer 2 */#define PCI230_Z2_CTC    0x17   /* 82C54 counter/timer control word */#define PCI230_ZCLK_SCE  0x1A   /* Group Z Clock Configuration Register */#define PCI230_ZGAT_SCE  0x1D   /* Group Z Gate Configuration Register */#define PCI230_INT_SCE   0x1E   /* ISR Interrupt source mask register/Interrupt status */  /* PCI230 i/o space 2 registers. */#define PCI230_DACCON  0x00#define PCI230_DACOUT1 0x02#define PCI230_DACOUT2 0x04#define PCI230_DACOUT3 0x06#define PCI230_ADCDATA 0x08#define PCI230_ADCCON  0x0A#define PCI230_ADCEN   0x0C#define PCI230_ADCG    0x0E/* Convertor related constants. */#define PCI230_DAC_SETTLE 5		/* Analogue output settling time in 祍 (DAC itself is 1祍 nominally). */  #define PCI230_ADC_SETTLE 1		/* Analogue input settling time in 祍 (ADC itself is 1.6祍 nominally but we poll anyway). */  #define PCI230_MUX_SETTLE 10	/* ADC MUX settling time in 礢 - 10祍 for se, 20祍 de. *//* DACCON values. */#define PCI230_DAC_BUSY_BIT		1#define PCI230_DAC_BIP_BIT		0/* ADCCON write values. */#define PCI230_ADC_TRIG_NONE		0#define PCI230_ADC_TRIG_SW 			1#define PCI230_ADC_TRIG_EXTP		2#define PCI230_ADC_TRIG_EXTN		3#define PCI230_ADC_TRIG_Z2CT0		4#define PCI230_ADC_TRIG_Z2CT1		5#define PCI230_ADC_TRIG_Z2CT2		6#define PCI230_ADC_IR_UNI			(0<<3)	/* Input range unipolar */#define PCI230_ADC_IR_BIP			(1<<3)	/* Input range bipolar */#define PCI230_ADC_IM_SE			(0<<4)	/* Input mode single ended */#define PCI230_ADC_IM_DIF			(1<<4)	/* Input mode differential */#define PCI230_ADC_FIFO_EN			(1<<8)#define PCI230_ADC_INT_FIFO_EMPTY	0#define PCI230_ADC_INT_FIFO_NEMPTY	(1<<9)#define PCI230_ADC_INT_FIFO_NHALF	(2<<9)#define PCI230_ADC_INT_FIFO_HALF	(3<<9)#define PCI230_ADC_INT_FIFO_NFULL	(4<<9)#define PCI230_ADC_INT_FIFO_FULL	(5<<9)#define PCI230_ADC_FIFO_RESET		(1<<12)#define PCI230_ADC_GLOB_RESET		(1<<13)#define PCI230_ADC_CONV				0xffff		/* Value to write to ADCDATA to trigger ADC conversion in sotware trigger mode *//* ADCCON read values. */#define PCI230_ADC_BUSY_BIT		15#define PCI230_ADC_FIFO_EMPTY	(1<<12)#define PCI230_ADC_FIFO_FULL	(1<<13)#define PCI230_ADC_FIFO_HALF	(1<<14)/* Group Z clock configuration register values. */#define PCI230_ZCLK_CT0			0#define PCI230_ZCLK_CT1			8#define PCI230_ZCLK_CT2			16#define PCI230_ZCLK_RES			24#define PCI230_ZCLK_SRC_PPCN	0 		/* The counter/timer's CLK input from the SK1 connector. */#define PCI230_ZCLK_SRC_10MHZ	1		/* The internal 10MHz clock. */ 	#define PCI230_ZCLK_SRC_1MHZ	2		/* The internal 1MHz clock. */ 	 	#define PCI230_ZCLK_SRC_100KHZ	3		/* The internal 100kHz clock. */ 	 	#define PCI230_ZCLK_SRC_10KHZ	4		/* The internal 10kHz clock. */  	#define PCI230_ZCLK_SRC_1KHZ	5		/* The internal 1kHz clock. */  	#define PCI230_ZCLK_SRC_OUTNM1	6		/* The output of the preceding counter/timer channel (OUT n-1). */ #define PCI230_ZCLK_SRC_EXTCLK	7		/* The dedicated external clock input for the group (X1/X2, Y1/Y2, Z1/Z2). */ #define PCI230_TIMEBASE_10MHZ	100		/* 10MHz => 100ns. *//* Interrupt enables/status register values. */#define PCI230_INT_DISABLE		0#define PCI230_INT_PPI_C0		1#define PCI230_INT_PPI_C3		2#define PCI230_INT_ADC			4#define PCI230_INT_ZCLK_CT1		32#define PCI230_TEST_BIT(val, n)	((val>>n)&1)	/* Assumes bits numbered with zero offset, ie. 0-15 *//* * Board descriptions for the two boards supported. */typedef struct pci230_board_struct{	char *name;	unsigned short id;	int ai_chans;	int ai_bits;	int have_ao;	int ao_chans;	int ao_bits;		int have_dio;}pci230_board;static pci230_board pci230_boards[] = {	{	name:		"Amplicon PCI230",	id:		PCI_DEVICE_ID_PCI230,	ai_chans:	16,	ai_bits:	12,	have_ao:	1,	ao_chans:	2,	ao_bits:	12,		have_dio:	1,	},	{	name:		"Amplicon PCI260",	id:		PCI_DEVICE_ID_PCI260,	ai_chans:	16,	ai_bits:	12,	have_ao:	0,	ao_chans:	0,	ao_bits:	0,		have_dio:	0,	},};static struct pci_device_id pci230_pci_table[] __devinitdata = {	{ PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0 }};MODULE_DEVICE_TABLE(pci, pci230_pci_table);/* * Useful for shorthand access to the particular board structure */#define n_pci230_boards (sizeof(pci230_boards)/sizeof(pci230_boards[0]))#define thisboard ((pci230_board *)dev->board_ptr)/* this structure is for data unique to this hardware driver.  If   several hardware drivers keep similar information in this structure,   feel free to suggest moving the variable to the comedi_device struct.  */struct pci230_private{	struct pci_dev *pci_dev;	lsampl_t ao_readback[2];  	/* Used for AO readback */	unsigned int pci_iobase;	/* PCI230's I/O space 1 */		/* Divisors for 8254 counter/timer. */    	unsigned int divisor0;	unsigned int divisor1;	unsigned int divisor2;	unsigned int int_en;		/* Interrupt enables bits. */		unsigned int ai_count;		/* Number of analogue input samples remaining. */	unsigned int ao_count;		/* Number of analogue output samples remaining. */	unsigned int ai_stop;  		/* Flag set when cmd->stop_src == TRIG_NONE - user chooses to stop continuous conversion by cancelation. */	unsigned int ao_stop;  		/* Flag set when cmd->stop_src == TRIG_NONE - user chooses to stop continuous conversion by cancelation. */	unsigned int ai_bipolar;	/* Set if bipolar input range so we know to mangle it. */	unsigned int ao_bipolar;	/* Set if bipolar output range so we know to mangle it. */	unsigned int ier;			/* Copy of interrupt enables/status register. */};#define devpriv ((struct pci230_private *)dev->private)/* PCI230 analogue input range table */ static comedi_lrange pci230_ai_range = { 7, {	BIP_RANGE(10),	BIP_RANGE(5),	BIP_RANGE(2.5),	BIP_RANGE(1.25),	UNI_RANGE(10),	UNI_RANGE(5),	UNI_RANGE(2.5)}};/* PCI230 analogue output range table */ static comedi_lrange pci230_ao_range = { 2, {	UNI_RANGE(10),	BIP_RANGE(10)}};/* * The comedi_driver structure tells the Comedi core module * which functions to call to configure/deconfigure (attach/detach) * the board, and also about the kernel module that contains * the device code. */static int pci230_attach(comedi_device *dev,comedi_devconfig *it);static int pci230_detach(comedi_device *dev);static comedi_driver driver_amplc_pci230={	driver_name:	"amplc_pci230",	module:		THIS_MODULE,	attach:		pci230_attach,	detach:		pci230_detach,};COMEDI_INITCLEANUP(driver_amplc_pci230);static int pci230_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int pci230_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int pci230_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int pci230_ct_insn_config(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int pci230_ct_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static void pci230_ns_to_timer(unsigned int *ns,int round);static void pci230_z2_ct0(comedi_device *dev, unsigned int *ns,int round);static void pci230_z2_ct1(comedi_device *dev, unsigned int *ns,int round);static void pci230_z2_ct2(comedi_device *dev, unsigned int *ns,int round);static void pci230_cancel_ct0(comedi_device *dev);static void pci230_cancel_ct1(comedi_device *dev);static void pci230_cancel_ct2(comedi_device *dev);static void pci230_interrupt(int irq, void *d, struct pt_regs *regs);static int pci230_ao_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static int pci230_ao_cmd(comedi_device *dev, comedi_subdevice *s);static int pci230_ao_cancel(comedi_device *dev, comedi_subdevice *s);static void pci230_handle_ao(comedi_device *dev, comedi_subdevice *s);static int pci230_ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static int pci230_ai_cmd(comedi_device *dev, comedi_subdevice *s);static int pci230_ai_cancel(comedi_device *dev, comedi_subdevice *s);static void pci230_handle_ai(comedi_device *dev, comedi_subdevice *s);static void pci230_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s);static void pci230_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s); static sampl_t pci230_ai_read(comedi_device *dev){	/* Read sample. */	sampl_t data = (sampl_t) inw(dev->iobase + PCI230_ADCDATA);	/* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower four bits reserved for expansion). */	data = data>>4;	/* If a bipolar range was specified, mangle it (twos complement->straight binary). */ 	if (devpriv->ai_bipolar) {		data ^= 1<<(thisboard->ai_bits-1);	}	return data;}static void pci230_ao_write(comedi_device *dev, sampl_t data, int chan){	/* If a bipolar range was specified, mangle it (straight binary->twos complement). */ 	if (devpriv->ao_bipolar) {		data ^= 1<<(thisboard->ao_bits-1);	}			/* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower four bits reserved for expansion). */	data = data<<4;			/* Write data. */	outw((unsigned int) data, dev->iobase + (((chan) == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2));}/* * Attach is called by the Comedi core to configure the driver * for a particular board.  If you specified a board_name array * in the driver structure, dev->board_ptr contains that * address. */static int pci230_attach(comedi_device *dev,comedi_devconfig *it){	comedi_subdevice *s;	int pci_iobase, iobase = 0;		/* PCI230's I/O spaces 1 and 2 respectively. */	struct pci_dev *pci_dev;	int i=0,irq_hdl;	printk("comedi%d: amplc_pci230\n",dev->minor);		/* Find card */	pci_for_each_dev(pci_dev){		if(pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)			continue;		for(i=0;i<n_pci230_boards;i++){			if(pci_dev->device == pci230_boards[i].id)break;		}		if(i<n_pci230_boards)break; 		printk("comedi%d: found an unknown Amplicon board, dev id=0x%04x\n",			dev->minor,pci_dev->device);	}	if(!pci_dev){		printk("comedi%d: amplc_pci230: No PCI230 found\n",dev->minor);		return -EIO;	}	dev->board_ptr = pci230_boards+i;		/* Read base addressses of the PCI230's two I/O regions from PCI configuration register. */	if(pci_enable_device(pci_dev)<0)return -EIO;	pci_iobase = pci_resource_start(pci_dev, 2);	iobase = pci_resource_start(pci_dev, 3);	printk("comedi%d: amplc_pci230: I/O region 1 0x%04x I/O region 2 0x%04x\n",dev->minor, pci_iobase, iobase);	/* Allocate the private structure area using alloc_private().	 * Macro defined in comedidev.h - memsets struct fields to 0. */	if((alloc_private(dev,sizeof(struct pci230_private)))<0)		return -ENOMEM;	devpriv->pci_dev = pci_dev;	/* Reserve I/O space 1. */	if(check_region(pci_iobase,PCI230_IO1_SIZE)<0){		printk("comedi%d: amplc_pci230: I/O space 1 conflict\n",dev->minor);		return -EIO;	}	request_region(pci_iobase,PCI230_IO1_SIZE,"PCI230");	devpriv->pci_iobase = pci_iobase;	/* Reserve I/O space 2. */	if(check_region(iobase,PCI230_IO2_SIZE)<0){		printk("comedi%d: amplc_pci230: I/O space 2 conflict\n",dev->minor);		return -EIO;	}	request_region(iobase,PCI230_IO2_SIZE,"PCI230");	dev->iobase = iobase;/* * Initialize dev->board_name.  Note that we can use the "thisboard" * macro now, since we just initialized it in the last line. */	dev->board_name = thisboard->name;	/* Register the interrupt handler. */	irq_hdl = comedi_request_irq(devpriv->pci_dev->irq, pci230_interrupt, SA_SHIRQ, "amplc_pci230", dev);	if(irq_hdl<0) {		printk("comedi%d: amplc_pci230: unable to register irq, commands will not be available %d\n", dev->minor, devpriv->pci_dev->irq);	}	else {		dev->irq = devpriv->pci_dev->irq;		printk("comedi%d: amplc_pci230: registered irq %d\n", dev->minor, devpriv->pci_dev->irq);	}/* * Allocate the subdevice structures.  alloc_subdevice() is a * convenient macro defined in comedidev.h. */	if(alloc_subdevices(dev, 4)<0)		return -ENOMEM;	s=dev->subdevices+0;	/* analog input subdevice */	s->type=COMEDI_SUBD_AI;	s->subdev_flags=SDF_READABLE|SDF_DIFF|SDF_GROUND;	s->n_chan=thisboard->ai_chans;	s->maxdata=(1<<thisboard->ai_bits)-1;	s->range_table=&pci230_ai_range;	s->insn_read = &pci230_ai_rinsn;	s->len_chanlist = thisboard->ai_chans;	/* Only register commands if the interrupt handler is installed. */	if(irq_hdl==0) {		dev->read_subdev=s;		s->do_cmd = &pci230_ai_cmd;		s->do_cmdtest = &pci230_ai_cmdtest;		s->cancel = pci230_ai_cancel;	}	s=dev->subdevices+1;	/* analog output subdevice */	s->type=COMEDI_SUBD_AO;	s->subdev_flags=SDF_WRITABLE;	s->n_chan=thisboard->ao_chans;;	s->maxdata=(1<<thisboard->ao_bits)-1;	s->range_table=&pci230_ao_range;	s->insn_write = &pci230_ao_winsn;	s->insn_read = &pci230_ao_rinsn;	s->len_chanlist = thisboard->ao_chans;	/* Only register commands if the interrupt handler is installed. */	if(irq_hdl==0) {		dev->write_subdev=s;		s->do_cmd = &pci230_ao_cmd;		s->do_cmdtest = &pci230_ao_cmdtest;		s->cancel = pci230_ao_cancel;	}	s=dev->subdevices+2;	/* digital i/o subdevice */	if(thisboard->have_dio){		subdev_8255_init(dev,s,NULL,(devpriv->pci_iobase + PCI230_PPI_X_A));	}else{		s->type = COMEDI_SUBD_UNUSED;	}	s=dev->subdevices+3;	/* timer subdevice */	s->type=COMEDI_SUBD_TIMER;	s->subdev_flags=SDF_READABLE;	s->n_chan=1;	s->maxdata=0xffff;	s->range_table=&range_digital;	s->insn_config = pci230_ct_insn_config;	s->insn_read = &pci230_ct_rinsn;	printk("attached\n");	return 1;}/* * _detach is called to deconfigure a device.  It should deallocate * resources.   * This function is also called when _attach() fails, so it should be * careful not to release resources that were not necessarily * allocated by _attach().  dev->private and dev->subdevices are

⌨️ 快捷键说明

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