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

📄 adl_pci9118.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				devpriv->ai_add_back=1;			} 		    	if (cmd->convert_src==TRIG_TIMER) { 				devpriv->usedma=0;	// use INT transfer if scanlist have only one channel			}		} 		if ((cmd->flags&TRIG_WAKE_EOS) &&		    (devpriv->ai_n_scanlen&1) &&		    (devpriv->ai_n_scanlen>1)) {				if (cmd->scan_begin_src==TRIG_FOLLOW) {					//vpriv->useeoshandle=1; // change DMA transfer block to fit EOS on every second call					devpriv->usedma=0;	// XXX maybe can be corrected to use 16 bit DMA				} else { // well, we must insert one sample to end of EOS to meet 32 bit transfer					devpriv->ai_add_back=1;					devpriv->usedma=1; // 16 bit DMA transfer				}		}		if ((!(cmd->flags&TRIG_WAKE_EOS)) &&		    (devpriv->ai_n_scanlen&1)) {			devpriv->usedma=1; // 16 bit DMA transfer		}	} else { // interrupt transfer don't need any correction		devpriv->usedma=0;	}		if ((devpriv->usedma==2)&&(devpriv->ai_data_len&3)) // if output buffer inn't alligned to 32 bit then use 16 bit DMA		devpriv->usedma=1;			// we need software S&H signal? It add  two samples before every scan as minimum	if (devpriv->usessh&&devpriv->softsshdelay) { 		devpriv->ai_add_front=2;		if ((devpriv->usedma==1)&&(devpriv->ai_add_back==1)) {// move it to front			devpriv->ai_add_front++;			devpriv->ai_add_back=0;		}		if (cmd->convert_arg<this_board->ai_ns_min) cmd->convert_arg=this_board->ai_ns_min;		addchans=devpriv->softsshdelay/cmd->convert_arg;		if (devpriv->softsshdelay%cmd->convert_arg) addchans++;		if (addchans>(devpriv->ai_add_front-1)) { // uff, still short :-(			devpriv->ai_add_front=addchans+1;			if (devpriv->usedma==1)				if ((devpriv->ai_add_front+devpriv->ai_n_chan+devpriv->ai_add_back)&1) devpriv->ai_add_front++; // round up to 32 bit			if (devpriv->usedma==2)				if (devpriv->ai_add_front&1) devpriv->ai_add_front++; // round up to 32 bit		}	} // well, we now know what must be all added		devpriv->ai_n_realscanlen= // what we must take from card in real to have ai_n_scanlen on output?	    (devpriv->ai_add_front+devpriv->ai_n_chan+devpriv->ai_add_back)*	    (devpriv->ai_n_scanlen / devpriv->ai_n_chan);	DPRINTK("2 usedma=%d realscan=%d af=%u n_chan=%d ab=%d n_scanlen=%d\n",		devpriv->usedma,		devpriv->ai_n_realscanlen, devpriv->ai_add_front, devpriv->ai_n_chan, 		devpriv->ai_add_back, devpriv->ai_n_scanlen);		// check and setup channel list	if (!check_channel_list(dev, s, devpriv->ai_n_chan, devpriv->ai_chanlist,		devpriv->ai_add_front, devpriv->ai_add_back)) return -EINVAL;	if (!setup_channel_list(dev, s, devpriv->ai_n_chan, devpriv->ai_chanlist, 		0, devpriv->ai_add_front, devpriv->ai_add_back, devpriv->usedma, 		devpriv->useeoshandle)) return -EINVAL;	// compute timers settings	// simplest way, fr=4Mhz/(tim1*tim2), channel manipulation without timers effect	if (((cmd->scan_begin_src==TRIG_FOLLOW)||(cmd->scan_begin_src==TRIG_EXT)||(cmd->scan_begin_src==TRIG_INT))&&(cmd->convert_src==TRIG_TIMER)) { // both timer is used for one time		if (cmd->scan_begin_src==TRIG_EXT) {			devpriv->ai_do=4;		} else {			devpriv->ai_do=1;		}		pci9118_calc_divisors(devpriv->ai_do, dev, s, 			&cmd->scan_begin_arg, &cmd->convert_arg, devpriv->ai_flags, 			devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, &devpriv->ai_divisor2, 			devpriv->usessh, devpriv->ai_add_front);		devpriv->ai_timer2=cmd->convert_arg;	}	if ((cmd->scan_begin_src==TRIG_TIMER)&&((cmd->convert_src==TRIG_TIMER)||(cmd->convert_src==TRIG_NOW))) { // double timed action		if (!devpriv->usedma) {			comedi_error(dev,"cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!");			return -EIO;		}				devpriv->ai_do=2;		pci9118_calc_divisors(devpriv->ai_do, dev, s, 			&cmd->scan_begin_arg, &cmd->convert_arg, devpriv->ai_flags, 			devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, &devpriv->ai_divisor2, 			devpriv->usessh, devpriv->ai_add_front);		devpriv->ai_timer1=cmd->scan_begin_arg;		devpriv->ai_timer2=cmd->convert_arg;	}	if ((cmd->scan_begin_src==TRIG_FOLLOW)&&(cmd->convert_src==TRIG_EXT)) { 		devpriv->ai_do=3;	}	start_pacer(dev, -1, 0, 0); // stop pacer	devpriv->AdControlReg=0; 	// bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA	outl(devpriv->AdControlReg,dev->iobase+PCI9118_ADCNTRL);	devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg;	// positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop	outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC);	comedi_udelay(1);	outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO	inl(dev->iobase+PCI9118_ADSTAT); // flush A/D and INT status register	inl(dev->iobase+PCI9118_INTSRC);        devpriv->ai_act_scan=0;	devpriv->ai_act_scanpos=0;	devpriv->ai_act_dmapos=0;        s->async->cur_chan=0;        devpriv->ai_buf_ptr=0;	if (devpriv->usedma) { 		ret=pci9118_ai_docmd_dma(dev, s);	} else {		ret=pci9118_ai_docmd_sampl(dev, s);	}	DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n");        return ret;}/*==============================================================================*/static int check_channel_list(comedi_device * dev, comedi_subdevice * s,	int n_chan, unsigned int *chanlist, int frontadd, int backadd){        unsigned int i, differencial=0, bipolar=0;	    	/* correct channel and range number check itself comedi/range.c */	if (n_chan<1) {		comedi_error(dev,"range/channel list is empty!");		return 0;                     }	if ((frontadd+n_chan+backadd)>s->len_chanlist) {		rt_printk("comedi%d: range/channel list is too long for actual configuration (%d>%d)!",dev->minor,n_chan,s->len_chanlist-frontadd-backadd);		return 0;             	}		if (CR_AREF(chanlist[0])==AREF_DIFF)		differencial=1;  // all input must be diff	if (CR_RANGE(chanlist[0])<PCI9118_BIPOLAR_RANGES)		bipolar=1;  // all input must be bipolar        if (n_chan > 1)		for (i=1 ; i<n_chan; i++) { // check S.E/diff			if ((CR_AREF(chanlist[i])==AREF_DIFF)!=(differencial)) {			    	comedi_error(dev,"Differencial and single ended inputs cann't be mixtured!");				return 0;             			}			if ((CR_RANGE(chanlist[i])<PCI9118_BIPOLAR_RANGES)!=(bipolar)) {			    	comedi_error(dev,"Bipolar and unipolar ranges cann't be mixtured!");				return 0;             			}			if ((!devpriv->usemux)&(differencial)&(CR_CHAN(chanlist[i])>=this_board->n_aichand)) {			    	comedi_error(dev,"If AREF_DIFF is used then is available only first 8 channels!");				return 0;             			}		}			return 1;}/*==============================================================================*/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 useeos){        unsigned int i, differencial=0, bipolar=0;	unsigned int scanquad, gain,ssh=0x00;	DPRINTK("adl_pci9118 EDBG: BGN: setup_channel_list(%d,.,%d,.,%d,%d,%d,%d)\n",		dev->minor, n_chan, rot, frontadd, backadd, usedma);	if (usedma==1) { rot=8; usedma=0; }	if (usedma) usedma=1;		if (CR_AREF(chanlist[0])==AREF_DIFF)		differencial=1;  // all input must be diff	if (CR_RANGE(chanlist[0])<PCI9118_BIPOLAR_RANGES)		bipolar=1;  // all input must be bipolar	// All is ok, so we can setup channel/range list	if (!bipolar) {	    devpriv->AdControlReg|=AdControl_UniP;	// set unibipolar	} else {	    devpriv->AdControlReg&=((~AdControl_UniP)&0xff);	// enable bipolar	}	if (differencial) {	    devpriv->AdControlReg|=AdControl_Diff;	// enable diff inputs	} else {	    devpriv->AdControlReg&=((~AdControl_Diff)&0xff);	// set single ended inputs	}        outl(devpriv->AdControlReg, dev->iobase+PCI9118_ADCNTRL); // setup mode	outl(2,dev->iobase+PCI9118_SCANMOD); // gods know why this sequence!	outl(0,dev->iobase+PCI9118_SCANMOD);	outl(1,dev->iobase+PCI9118_SCANMOD);	#ifdef PCI9118_PARANOIDCHECK	devpriv->chanlistlen=n_chan;	for (i=0; i<(PCI9118_CHANLEN+1); i++) devpriv->chanlist[i]=0x55aa;#endif		if (frontadd) {  // insert channels for S&H		ssh=devpriv->softsshsample;		DPRINTK("FA: %04x: ",ssh);		for (i=0; i<frontadd; i++) {  // store range list to card			scanquad=CR_CHAN(chanlist[0]);	// get channel number;			gain=CR_RANGE(chanlist[0]);		// get gain number			scanquad|=((gain & 0x03)<<8);			outl(scanquad|ssh,dev->iobase+PCI9118_GAIN);			DPRINTK("%02x ",scanquad|ssh);			ssh=devpriv->softsshhold;		}		DPRINTK("\n ");	}		DPRINTK("SL: ",ssh);	for (i=0; i<n_chan; i++) {  // store range list to card		scanquad=CR_CHAN(chanlist[i]);	// get channel number;#ifdef PCI9118_PARANOIDCHECK		devpriv->chanlist[i^usedma]=(scanquad & 0xf)<<rot;#endif		gain=CR_RANGE(chanlist[i]);		// get gain number		scanquad|=((gain & 0x03)<<8);		outl(scanquad|ssh,dev->iobase+PCI9118_GAIN);		DPRINTK("%02x ",scanquad|ssh);	}	DPRINTK("\n ");	if (backadd) {  // insert channels for fit onto 32bit DMA		DPRINTK("BA: %04x: ",ssh);		for (i=0; i<backadd; i++) {  // store range list to card			scanquad=CR_CHAN(chanlist[0]);	// get channel number;			gain=CR_RANGE(chanlist[0]);		// get gain number			scanquad|=((gain & 0x03)<<8);			outl(scanquad|ssh,dev->iobase+PCI9118_GAIN);			DPRINTK("%02x ",scanquad|ssh);		}		DPRINTK("\n ");	}	#ifdef PCI9118_PARANOIDCHECK	devpriv->chanlist[n_chan^usedma]=devpriv->chanlist[0^usedma]; // for 32bit oerations	if (useeos) {		for (i=1; i<n_chan; i++) {  // store range list to card			devpriv->chanlist[(n_chan+i)^usedma]=				(CR_CHAN(chanlist[i]) & 0xf)<<rot;		}		devpriv->chanlist[(2*n_chan)^usedma]=devpriv->chanlist[0^usedma]; // for 32bit oerations		useeos=2;	} else {		useeos=1;	}#ifdef PCI9118_EXTDEBUG	DPRINTK("CHL: ");	for (i=0; i<=(useeos*n_chan); i++) {		DPRINTK("%04x ",devpriv->chanlist[i]);	}	DPRINTK("\n ");#endif#endif	outl(0,dev->iobase+PCI9118_SCANMOD);	// close scan queue//	comedi_udelay(100);				// important delay, or first sample will be cripled	DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n");	return 1; // we can serve this with scan logic}/*==============================================================================  calculate 8254 divisors if they are used for dual timing*/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){	DPRINTK("adl_pci9118 EDBG: BGN: pci9118_calc_divisors(%d,%d,.,%u,%u,%u,%d,.,.,,%u,%u)\n",		mode, dev->minor, *tim1, *tim2, flags, chans, usessh, chnsshfront);        switch (mode) {	case 1:	case 4:		if (*tim2<this_board->ai_ns_min) *tim2=this_board->ai_ns_min;		i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,div1,div2,tim2,flags&TRIG_ROUND_NEAREST);		DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u\n",devpriv->i8254_osc_base,*div1,*div2,*tim1);		break;	case 2:		if (*tim2<this_board->ai_ns_min) *tim2=this_board->ai_ns_min;		DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		*div1=*tim2/devpriv->i8254_osc_base; // convert timer (burst)		DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		if (*div1<this_board->ai_pacer_min) *div1=this_board->ai_pacer_min;		DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		*div2=*tim1/devpriv->i8254_osc_base; // scan timer		DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		*div2=*div2/ *div1;						// major timer is c1*c2		DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		if (*div2<chans) *div2=chans;		DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		*tim2=*div1 * devpriv->i8254_osc_base; // real convert timer		if (usessh & (chnsshfront==0)) // use BSSH signal			if (*div2<(chans+2))				 *div2=chans+2;				 		DPRINTK("7 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2);		*tim1= *div1 * *div2 * devpriv->i8254_osc_base;		DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u timer2=%u\n",devpriv->i8254_osc_base,*div1,*div2,*tim1,*tim2);		break;	}	DPRINTK("adl_pci9118 EDBG: END: pci9118_calc_divisors(%u,%u)\n",		*div1, *div2);}   /*==============================================================================*/static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) {        outl(0x74, dev->iobase + PCI9118_CNTCTRL);        outl(0xb4, dev->iobase + PCI9118_CNTCTRL);//	outl(0x30, dev->iobase + PCI9118_CNTCTRL);        comedi_udelay(1);          if ((mode==1)||(mode==2)||(mode==4)) {		outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2);		outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2);		outl(divisor1  & 0xff, dev->iobase + PCI9118_CNT1);		outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1);        }}/*==============================================================================*/static int pci9118_exttrg_add(comedi_device * dev, unsigned char source){	if (source>3) return -1; // incorrect source	devpriv->exttrg_users|=(1<<source);	devpriv->IntControlReg|=Int_DTrg;	outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL);	outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)|0x1f00, devpriv->iobase_a+AMCC_OP_REG_INTCSR); // allow INT in AMCC	return 0;}/* ==============================================================================*/static int pci9118_exttrg_del(comedi_device * dev, unsigned char source){	if (source>3) return -1; // incorrect source	devpriv->exttrg_users&=~(1<<source);	if (!devpriv->exttrg_users) { // shutdown ext trg intterrupts		devpriv->IntControlReg&=~Int_DTrg;		if (!devpriv->IntControlReg) // all IRQ disabled			outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)&(~0x00001f00), devpriv->iobase_a+AMCC_OP_REG_INTCSR); // disable int in AMCC		outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL);	}	return 0;}/* =============================================================================

⌨️ 快捷键说明

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