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

📄 adl_pci9118.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  comedi/drivers/adl_pci9118.c * *  hardware driver for ADLink cards: *   card:   PCI-9118DG, PCI-9118HG, PCI-9118HR *   driver: pci9118dg,  pci9118hg,  pci9118hr * * Author: Michal Dobes <dobes@tesnet.cz> **//*Driver: adl_pci9118.oDescription: Adlink PCI-9118DG, PCI-9118HG, PCI-9118HRAuthor: Michal Dobes <dobes@tesnet.cz>Devices: [ADLink] PCI-9118DG (pci9118dg), PCI-9118HG (pci9118hg),  PCI-9118HR (pci9118hr)Status: worksThis driver supports AI, AO, DI and DO subdevices.AI subdevice supports cmd and insn interface,other subdevices support only insn interface.For AI:- If cmd->scan_begin_src=TRIG_EXT then trigger input is TGIN (pin 46).- If cmd->convert_src=TRIG_EXT then trigger input is EXTTRG (pin 44).- If cmd->start_src/stop_src=TRIG_EXT then trigger input is TGIN (pin 46).- It is not neccessary to have cmd.scan_end_arg=cmd.chanlist_len but  cmd.scan_end_arg modulo cmd.chanlist_len must by 0.- If return value of cmdtest is 5 then you've bad channel list  (it isn't possible mixture S.E. and DIFF inputs or bipolar and unipolar  ranges).There are some hardware limitations:a) You cann't use mixture of unipolar/bipoar ranges or differencial/single    ended inputs.b) DMA transfers must have the length aligned to two samples (32 bit),   so there is some problems if cmd->chanlist_len is odd. This driver tries   bypass this with adding one sample to the end of the every scan and discard   it on output but this cann't be used if cmd->scan_begin_src=TRIG_FOLLOW   and is used flag TRIG_WAKE_EOS, then driver switch to interrupt driven mode    with interrupt after every sample.c) If isn't used DMA then you can use only mode where    cmd->scan_begin_src=TRIG_FOLLOW.Configuration options:  [0] - PCI bus of device (optional)  [1] - PCI slot of device (optional)          If bus/slot is not specified, then first available PCI          card will be used.  [2] - 0= standard 8 DIFF/16 SE channels configuration        n= external multiplexer connected, 1<=n<=256  [3] - 0=autoselect DMA or EOC interrupts operation        1=disable DMA mode        3=disable DMA and INT, only insn interface will work  [4] - sample&hold signal - card can generate signal for external S&H board        0=use SSHO (pin 45) signal is generated in onboard hardware S&H logic        0!=use ADCHN7 (pin 23) signal is generated from driver, number            say how long delay is requested in ns and sign polarity of the hold           (in this case external multiplexor can serve only 128 channels)  [5] - 0=stop measure on all hardware errors        2|=ignore ADOR - A/D Overrun status	8|=ignore Bover - A/D Burst Mode Overrun status	256|=ignore nFull - A/D FIFO Full status*/#include <linux/comedidev.h>#include <linux/delay.h>#include "amcc_s5933.h"#include "8253.h"#include "comedi_fc.h"#define PCI9118_PARANOIDCHECK		/* if defined, then is used code which control correct channel number on every 12 bit sample */#undef PCI9118_EXTDEBUG		/* if defined then driver prints a lot of messages */#undef DPRINTK#ifdef PCI9118_EXTDEBUG#define DPRINTK(fmt, args...) rt_printk(fmt, ## args)#else#define DPRINTK(fmt, args...)#endif#define IORANGE_9118 	64		/* I hope */#define PCI9118_CHANLEN	255		/* len of chanlist, some source say 256, but reality looks like 255 :-( */#define PCI9118_CNT0	0x00		/* R/W: 8254 couter 0 */#define PCI9118_CNT1	0x04		/* R/W: 8254 couter 0 */#define PCI9118_CNT2	0x08		/* R/W: 8254 couter 0 */#define PCI9118_CNTCTRL	0x0c		/* W:   8254 counter control */#define PCI9118_AD_DATA	0x10		/* R:   A/D data */#define PCI9118_DA1	0x10		/* W:   D/A registers */#define PCI9118_DA2	0x14#define PCI9118_ADSTAT	0x18		/* R:   A/D status register */#define PCI9118_ADCNTRL	0x18		/* W:   A/D control register */#define PCI9118_DI	0x1c		/* R:   digi input register */#define PCI9118_DO	0x1c		/* W:   digi output register */#define PCI9118_SOFTTRG	0x20		/* W:   soft trigger for A/D */#define PCI9118_GAIN	0x24		/* W:   A/D gain/channel register */#define PCI9118_BURST	0x28		/* W:   A/D burst number register */#define PCI9118_SCANMOD	0x2c		/* W:   A/D auto scan mode */#define PCI9118_ADFUNC	0x30		/* W:   A/D function register */#define PCI9118_DELFIFO	0x34		/* W:   A/D data FIFO reset */#define PCI9118_INTSRC	0x38		/* R:   interrupt reason register */#define PCI9118_INTCTRL	0x38		/* W:   interrupt control register */// bits from A/D control register (PCI9118_ADCNTRL)#define AdControl_UniP	0x80		/* 1=bipolar, 0=unipolar */#define AdControl_Diff	0x40		/* 1=differential, 0= single end inputs */#define AdControl_SoftG	0x20		/* 1=8254 counter works, 0=counter stops */#define	AdControl_ExtG	0x10		/* 1=8254 countrol controlled by TGIN(pin 46), 0=controled by SoftG */#define AdControl_ExtM	0x08		/* 1=external hardware trigger (pin 44), 0=internal trigger */#define AdControl_TmrTr	0x04		/* 1=8254 is iternal trigger source, 0=software trigger is source (register PCI9118_SOFTTRG) */#define AdControl_Int	0x02		/* 1=enable INT, 0=disable */#define AdControl_Dma	0x01		/* 1=enable DMA, 0=disable */// bits from A/D function register (PCI9118_ADFUNC)#define AdFunction_PDTrg	0x80	/* 1=positive, 0=negative digital trigger (only positive is correct) */#define AdFunction_PETrg	0x40	/* 1=positive, 0=negative external trigger (only positive is correct) */#define AdFunction_BSSH		0x20	/* 1=with sample&hold, 0=without */#define AdFunction_BM		0x10	/* 1=burst mode, 0=normal mode */#define AdFunction_BS		0x08	/* 1=burst mode start, 0=burst mode stop */#define AdFunction_PM		0x04	/* 1=post trigger mode, 0=not post trigger */#define AdFunction_AM		0x02	/* 1=about trigger mode, 0=not about trigger */#define AdFunction_Start	0x01	/* 1=trigger start, 0=trigger stop */// bits from A/D status register (PCI9118_ADSTAT)#define AdStatus_nFull	0x100		/* 0=FIFO full (fatal), 1=not full */#define AdStatus_nHfull	0x080		/* 0=FIFO half full, 1=FIFO not half full */#define AdStatus_nEpty	0x040		/* 0=FIFO empty, 1=FIFO not empty */#define AdStatus_Acmp	0x020		/*  */#define AdStatus_DTH	0x010		/* 1=external digital trigger */#define AdStatus_Bover	0x008		/* 1=burst mode overrun (fatal) */#define AdStatus_ADOS	0x004		/* 1=A/D over speed (warning) */#define AdStatus_ADOR	0x002		/* 1=A/D overrun (fatal) */#define AdStatus_ADrdy	0x001		/* 1=A/D already ready, 0=not ready */// bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL)// 1=interrupt occur, enable source,  0=interrupt not occur, disable source#define Int_Timer	0x08		/* timer interrupt */#define Int_About	0x04		/* about trigger complete */#define Int_Hfull	0x02		/* A/D FIFO hlaf full */#define Int_DTrg	0x01		/* external digital trigger */#define START_AI_EXT	0x01		/* start measure on external trigger */#define STOP_AI_EXT	0x02		/* stop measure on external trigger */#define START_AI_INT	0x04		/* start measure on internal trigger */#define STOP_AI_INT	0x08		/* stop measure on internal trigger */#define EXTTRG_AI	0		/* ext trg is used by AI */static comedi_lrange range_pci9118dg_hr={ 8, {	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)	}};static comedi_lrange range_pci9118hg={ 8, {	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)	}};#define PCI9118_BIPOLAR_RANGES	4	/* used for test on mixture of BIP/UNI ranges */static int pci9118_attach(comedi_device *dev,comedi_devconfig *it);static int pci9118_detach(comedi_device *dev);static unsigned short pci_list_builded=0;	/*=1 list of cards is know */typedef struct {	char 		*name;		// driver name	int		vendor_id;	// PCI vendor a device ID of card	int		device_id;	int		iorange_amcc;	// iorange for own S5933 region	int		iorange_9118;	// pass thru card region size	int 		n_aichan;	// num of A/D chans	int 		n_aichand;	// num of A/D chans in diff mode	int		mux_aichan;	// num of A/D chans with external multiplexor	int		n_aichanlist;	// len of chanlist	int 		n_aochan;	// num of D/A chans	int		ai_maxdata;	// resolution of A/D	int		ao_maxdata;	// resolution of D/A	comedi_lrange	*rangelist_ai;	// rangelist for A/D	comedi_lrange	*rangelist_ao;	// rangelist for D/A	unsigned int	ai_ns_min;	// max sample speed of card v ns	unsigned int	ai_pacer_min;	// minimal pacer value (c1*c2 or c1 in burst)	int		half_fifo_size; // size of FIFO/2	} boardtype;static struct pci_device_id pci9118_pci_table[] __devinitdata = {	{ PCI_VENDOR_ID_AMCC, 0x80d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0 }};MODULE_DEVICE_TABLE(pci, pci9118_pci_table);static boardtype boardtypes[] ={	{"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9,	 AMCC_OP_REG_SIZE, IORANGE_9118,	 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,	 &range_pci9118dg_hr, &range_bipolar10,	 3000, 12, 512 },	{"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9,	 AMCC_OP_REG_SIZE, IORANGE_9118,	 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, 	 &range_pci9118hg, &range_bipolar10,	 3000, 12, 512 },	{"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9,	 AMCC_OP_REG_SIZE, IORANGE_9118,	 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff, 	 &range_pci9118dg_hr,    &range_bipolar10,	 10000, 40, 512 },};#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))static comedi_driver driver_pci9118={	driver_name:	"adl_pci9118",	module:		THIS_MODULE,	attach:		pci9118_attach,	detach:		pci9118_detach,	num_names:	n_boardtypes,	board_name:	boardtypes,	offset:		sizeof(boardtype),};COMEDI_INITCLEANUP(driver_pci9118);typedef struct{	int			iobase_a;	// base+size for AMCC chip	struct pcilst_struct	*amcc;		// ptr too AMCC data	unsigned int		master;		// master capable	unsigned char		allocated;	// we have blocked card	struct pci_dev		*pcidev;		// ptr to actual pcidev	unsigned int		usemux;		// we want to use external multiplexor!#ifdef PCI9118_PARANOIDCHECK	unsigned short		chanlist[PCI9118_CHANLEN+1]; // list of scaned channel	unsigned char		chanlistlen;	// number of scanlist#endif	unsigned char		AdControlReg;	// A/D control register	unsigned char		IntControlReg;	// Interrupt control register	unsigned char		AdFunctionReg;	// A/D function register	char			valid;		// driver is ok	char			ai_neverending;	// we do unlimited AI	unsigned int		i8254_osc_base;	// frequence of onboard oscilator	unsigned int		ai_do;		// what do AI? 0=nothing, 1 to 4 mode	unsigned int		ai_act_scan;// how many scans we finished	unsigned int 		ai_buf_ptr;	// data buffer ptr in samples	unsigned int 		ai_n_chan;// how many channels is measured	unsigned int 		ai_n_scanlen;// len of actual scanlist	unsigned int 		ai_n_realscanlen;// what we must transfer for one outgoing scan include front/back adds	unsigned int 		ai_act_scanpos; // position in actual scan	unsigned int		ai_act_dmapos;	// position in actual real stream	unsigned int 		ai_add_front; // how many channels we must add before scan to satisfy S&H?	unsigned int 		ai_add_back; // how many channels we must add before scan to satisfy DMA?	unsigned int		*ai_chanlist;// actaul chanlist	unsigned int		ai_timer1;		unsigned int		ai_timer2;	unsigned int		ai_flags;	char			ai12_startstop;	// measure can start/stop on external trigger	unsigned int		ai_divisor1,ai_divisor2; // divisors for start of measure on external start	unsigned int		ai_data_len;	sampl_t 		*ai_data;	sampl_t			ao_data[2];	// data output buffer	unsigned int		ai_scans;	// number of scans to do	char			dma_doublebuf;	// we can use double buffring	unsigned int		dma_actbuf;	// which buffer is used now	sampl_t 		*dmabuf_virt[2];	// pointers to begin of DMA buffer	unsigned long 		dmabuf_hw[2];	// hw address of DMA buff	unsigned int		dmabuf_size[2];	// size of dma buffer in bytes	unsigned int		dmabuf_use_size[2];	// which size we may now used for transfer	unsigned int		dmabuf_used_size[2];	// which size was trully used	unsigned int		dmabuf_panic_size[2];		unsigned int		dmabuf_samples[2];	// size in samples	int			dmabuf_pages[2];	// number of pages in buffer	unsigned char		cnt0_users;	// bit field of 8254 CNT0 users (0-unused, 1-AO, 2-DI, 3-DO)	unsigned char		exttrg_users;	// bit field of external trigger users (0-AI, 1-AO, 2-DI, 3-DO)	unsigned int		cnt0_divisor;	// actual CNT0 divisor	int			(*dma_ai_read_block)(comedi_device *, comedi_subdevice *, void *, int *, int *); // ptr to actual transfer function from DMA buffer	void			(*int_ai_func)(comedi_device *, comedi_subdevice *,unsigned short, unsigned int, unsigned short); // ptr to actual interrupt AI function	unsigned char		ai16bits;	// =1 16 bit card	unsigned char		usedma;		// =1 use DMA transfer and not INT	unsigned char		useeoshandle;	// =1 change WAKE_EOS DMA transfer to fit on every second	unsigned char		usessh;		// =1 turn on S&H support	int			softsshdelay;	// >0 use software S&H, numer is requested delay in ns	unsigned char		softsshsample;	// polarity of S&H signal in sample state	unsigned char		softsshhold;	// polarity of S&H signal in hold state	unsigned int		ai_maskerr;	// which warning was printed	unsigned int		ai_maskharderr;	// on which error bits stops	unsigned int		ai_inttrig_start;// TRIG_INT for start}pci9118_private;#define devpriv ((pci9118_private *)dev->private)#define this_board ((boardtype *)dev->board_ptr)/*==============================================================================*/static int check_channel_list(comedi_device * dev, comedi_subdevice * s,	int n_chan, unsigned int *chanlist, int frontadd, int backadd);static int setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan,	unsigned int *chanlist,int rot, int frontadd, int backadd, int usedma, char eoshandle);static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);static int pci9118_reset(comedi_device *dev);static int pci9118_exttrg_add(comedi_device * dev, unsigned char source);static int pci9118_exttrg_del(comedi_device * dev, unsigned char source);static int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s);static void pci9118_calc_divisors(char mode, comedi_device * dev, comedi_subdevice * s, 	unsigned int *tim1, unsigned int *tim2, unsigned int flags, 	int chans, unsigned int *div1, unsigned int *div2,	char usessh, unsigned int chnsshfront);/*==============================================================================*/static int pci9118_insn_read_ai(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){	int n,timeout;	devpriv->AdControlReg=AdControl_Int & 0xff;	devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg;	outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC);// positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop	if (!setup_channel_list(dev,s,1,&insn->chanspec, 0, 0, 0, 0, 0))  return -EINVAL;	outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO	for (n=0; n<insn->n; n++) {		outw(0, dev->iobase+PCI9118_SOFTTRG); /* start conversion */		comedi_udelay(2);    		timeout=100;    		while (timeout--) {			if (inl(dev->iobase+PCI9118_ADSTAT) & AdStatus_ADrdy) goto conv_finish;			comedi_udelay(1);    		}    		comedi_error(dev,"A/D insn timeout");    		data[n]=0;		outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO    		return -ETIME;conv_finish:		if (devpriv->ai16bits) {    			data[n] = (inl(dev->iobase+PCI9118_AD_DATA) & 0xffff) ^ 0x8000;		} else {    			data[n] = (inw(dev->iobase+PCI9118_AD_DATA)>>4) & 0xfff; 		}	}	outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO	return n;}/*==============================================================================*/static int pci9118_insn_write_ao(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){	int n,chanreg,ch;

⌨️ 快捷键说明

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