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

📄 ni_mio_common.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef DEBUG_INTERRUPT	rt_printk("ni_mio_common: interrupt: a_status=%04x m0_status=%08x\n",		status, m_status);	ni_mio_print_status_a(status);#endif#ifdef PCIDMA	/* Currently, mite.c requires us to handle LINKC and DONE */	if(m_status & CHSR_LINKC){		ni_sync_ai_dma(devpriv->mite, dev);	}	if(m_status & CHSR_DONE){		writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR +			CHAN_OFFSET(AI_DMA_CHAN));	}	if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){		printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status);		//mite_print_chsr(m_status);		mite_dma_disarm(devpriv->mite, AI_DMA_CHAN );		writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR +			CHAN_OFFSET(AI_DMA_CHAN));		//disable_irq(dev->irq);	}#endif	/* test for all uncommon interrupt events at the same time */	if(status&(AI_Overrun_St|AI_Overflow_St|AI_SC_TC_Error_St|AI_SC_TC_St|AI_START1_St)){		if(status==0xffff){			rt_printk("ni_mio_common: a_status=0xffff.  Card removed?\n");			/* we probably aren't even running a command now,			 * so it's a good idea to be careful. */			if(s->subdev_flags&SDF_RUNNING){				s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;				//comedi_event(dev,s,s->async->events);			}			return;		}		if(status&(AI_Overrun_St|AI_Overflow_St|AI_SC_TC_Error_St)){			rt_printk("ni_mio_common: ai error a_status=%04x\n",				status);			ni_mio_print_status_a(status);			ni_ai_reset(dev,dev->subdevices);			win_out(AI_Error_Interrupt_Ack, Interrupt_A_Ack_Register);			shutdown_ai_command( dev );			s->async->events |= COMEDI_CB_ERROR;			comedi_event(dev,s,s->async->events);			return;		}		if(status&AI_SC_TC_St){#ifdef DEBUG_INTERRUPT			rt_printk("ni_mio_common: SC_TC interrupt\n");#endif			if(!devpriv->ai_continuous){				shutdown_ai_command( dev );			}			ack|=AI_SC_TC_Interrupt_Ack;		}		if(status&AI_START1_St){			ack|=AI_START1_Interrupt_Ack;		}	}#ifndef PCIDMA	if(status&AI_FIFO_Half_Full_St){		ni_handle_fifo_half_full(dev);	}#endif // !PCIDMA	if( (status & AI_STOP_St) ){		if(devpriv->aimode==AIMODE_SCAN){#ifdef PCIDMA			int bytes_in_transit;			do{				bytes_in_transit = mite_bytes_in_transit( devpriv->mite, AI_DMA_CHAN );				ni_sync_ai_dma(devpriv->mite, dev);			}while( ( s->async->events & COMEDI_CB_EOS ) == 0 &&				bytes_in_transit );#else			ni_handle_fifo_dregs(dev);			s->async->events |= COMEDI_CB_EOS;#endif		}		/* handle special case of single scan using AI_End_On_End_Of_Scan */		if( s->async->cmd.stop_src == TRIG_COUNT && s->async->cmd.stop_arg == 1 ){			shutdown_ai_command( dev );		}		/* we need to ack the START, also */		ack|=AI_STOP_Interrupt_Ack|AI_START_Interrupt_Ack;	}	if(devpriv->aimode==AIMODE_SAMPLE){		ni_handle_fifo_dregs(dev);		//s->async->events |= COMEDI_CB_SAMPLE;	}	if(ack) win_out(ack,Interrupt_A_Ack_Register);	comedi_event(dev,s,s->async->events);#ifdef DEBUG_INTERRUPT	status=win_in(AI_Status_1_Register);	if(status&Interrupt_A_St){		printk("handle_a_interrupt: BUG, didn't clear interrupt. disabling.\n");                win_out(0,Interrupt_Control_Register);	}#endif}static void handle_b_interrupt(comedi_device *dev,unsigned short b_status, unsigned int m_status){	comedi_subdevice *s=dev->subdevices+1;	//unsigned short ack=0;#ifdef DEBUG_INTERRUPT	rt_printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",		b_status,m_status);	ni_mio_print_status_b(b_status);#endif#ifdef PCIDMA	/* Currently, mite.c requires us to handle LINKC and DONE */	if(m_status & CHSR_LINKC){		mite_handle_b_linkc(devpriv->mite, dev);	}	if(m_status & CHSR_DONE){		writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR +			CHAN_OFFSET(AO_DMA_CHAN));	}	if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){		printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status);		//mite_print_chsr(m_status);		mite_dma_disarm(devpriv->mite, AO_DMA_CHAN );		writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR +			CHAN_OFFSET(AO_DMA_CHAN));       }#endif	if(b_status==0xffff)return;	if(b_status&AO_Overrun_St){		rt_printk("ni_mio_common: AO FIFO underrun status=0x%04x status2=0x%04x\n",b_status,win_in(AO_Status_2_Register));		ni_ao_reset(dev,s);		s->async->events |= COMEDI_CB_OVERFLOW;	}	if(b_status&AO_BC_TC_St){		MDPRINTK("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n",b_status,win_in(AO_Status_2_Register));		ni_ao_reset(dev,s);		s->async->events |= COMEDI_CB_EOA;	}#ifndef PCIDMA	if(b_status&AO_FIFO_Request_St){		int ret;		ret = ni_ao_fifo_half_empty(dev,s);		if(!ret){			rt_printk("ni_mio_common: AO buffer underrun\n");			ni_set_bits(dev, Interrupt_B_Enable_Register,				AO_FIFO_Interrupt_Enable|AO_Error_Interrupt_Enable, 0);			s->async->events |= COMEDI_CB_OVERFLOW;		}	}#endif	b_status=win_in(AO_Status_1_Register);	if(b_status&Interrupt_B_St){		if(b_status&AO_FIFO_Request_St){			rt_printk("ni_mio_common: AO buffer underrun\n");		}		rt_printk("Ack! didn't clear AO interrupt. b_status=0x%04x\n",b_status);		ni_set_bits(dev,Interrupt_B_Enable_Register,~0,0);		ni_ao_reset(dev,s);		s->async->events |= COMEDI_CB_OVERFLOW;	}	comedi_event(dev,s,s->async->events);}#ifdef DEBUG_STATUS_Astatic char *status_a_strings[]={	"passthru0","fifo","G0_gate","G0_TC",	"stop","start","sc_tc","start1",	"start2","sc_tc_error","overflow","overrun",	"fifo_empty","fifo_half_full","fifo_full","interrupt_a"};static void ni_mio_print_status_a(int status){	int i;	rt_printk("A status:");	for(i=15;i>=0;i--){		if(status&(1<<i)){			rt_printk(" %s",status_a_strings[i]);		}	}	rt_printk("\n");}#endif#ifdef DEBUG_STATUS_Bstatic char *status_b_strings[]={	"passthru1","fifo","G1_gate","G1_TC",	"UI2_TC","UPDATE","UC_TC","BC_TC",	"start1","overrun","start","bc_tc_error",	"fifo_empty","fifo_half_full","fifo_full","interrupt_b"};static void ni_mio_print_status_b(int status){	int i;	rt_printk("B status:");	for(i=15;i>=0;i--){		if(status&(1<<i)){			rt_printk(" %s",status_b_strings[i]);		}	}	rt_printk("\n");}#endif#ifndef PCIDMAstatic void ni_ao_fifo_load(comedi_device *dev,comedi_subdevice *s, int n){	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	int chan;	int i;	sampl_t d;	u32 packed_data;	int range;	int offset;	int err = 1;	offset = 1 << (boardtype.aobits - 1);	chan = async->cur_chan;	for(i=0;i<n;i++){		err &= comedi_buf_get(async, &d);		if(err == 0) break;		range = CR_RANGE(cmd->chanlist[chan]);		if(!boardtype.ao_unipolar || !(range & 1)){			d -= offset;		}		if( boardtype.ao_671x ){			packed_data = d & 0xffff;			err &= comedi_buf_get(async, &d);			if(err == 0) break;			d -= offset;			chan++;			i++;			packed_data |= ( d << 16 ) & 0xffff0000;			ni_writel( packed_data, DAC_FIFO_Data_611x );		}else{			ni_writew(d, DAC_FIFO_Data);		}		chan++;		chan %= cmd->chanlist_len;	}	async->cur_chan = chan;	if(err==0){		async->events |= COMEDI_CB_OVERFLOW;	}}/* *  There's a small problem if the FIFO gets really low and we *  don't have the data to fill it.  Basically, if after we fill *  the FIFO with all the data available, the FIFO is _still_ *  less than half full, we never clear the interrupt.  If the *  IRQ is in edge mode, we never get another interrupt, because *  this one wasn't cleared.  If in level mode, we get flooded *  with interrupts that we can't fulfill, because nothing ever *  gets put into the buffer. * *  This kind of situation is recoverable, but it is easier to *  just pretend we had a FIFO underrun, since there is a good *  chance it will happen anyway.  This is _not_ the case for *  RT code, as RT code might purposely be running close to the *  metal.  Needs to be fixed eventually. */static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s){	int n;	n = comedi_buf_read_n_available(s->async);	if(n==0){		s->async->events |= COMEDI_CB_OVERFLOW;		return 0;	}	n /= sizeof(sampl_t);	if(n>boardtype.ao_fifo_depth/2)		n=boardtype.ao_fifo_depth/2;	ni_ao_fifo_load(dev,s,n);	s->async->events |= COMEDI_CB_BLOCK;	return 1;}static int ni_ao_prep_fifo(comedi_device *dev,comedi_subdevice *s){	int n;	/* reset fifo */	win_out(0,DAC_FIFO_Clear);	/* load some data */	n = comedi_buf_read_n_available(s->async);	if(n==0)return 0;	n /= sizeof(sampl_t);	if(n>boardtype.ao_fifo_depth)		n=boardtype.ao_fifo_depth;	ni_ao_fifo_load(dev,s,n);	return n;}static void ni_ai_fifo_read(comedi_device *dev,comedi_subdevice *s,	int n){	comedi_async *async = s->async;	int i;	u32 dl;	sampl_t data;	unsigned int mask;	int err = 1;	mask=(1<<boardtype.adbits)-1;	if(boardtype.reg_611x){		for( i = 0; i < n / 2; i++ ){			dl=ni_readl(ADC_FIFO_Data_611x);			/* This may get the hi/lo data in the wrong order */			data = (dl>>16) & 0xffff;			data += devpriv->ai_offset[ async->cur_chan++ ];			err &= comedi_buf_put(s->async, data);			async->cur_chan %= async->cmd.chanlist_len;			data = dl & 0xffff;			data += devpriv->ai_offset[ async->cur_chan++ ];			err &= comedi_buf_put(s->async, data);			async->cur_chan %= async->cmd.chanlist_len;		}		/* Check if there's a single sample stuck in the FIFO */		if( n % 2){			dl=ni_readl(ADC_FIFO_Data_611x);			data = dl & 0xffff;			data += devpriv->ai_offset[ async->cur_chan++ ];			err &= comedi_buf_put(s->async, data);			async->cur_chan %= async->cmd.chanlist_len;		}	}else{		for(i=0;i<n;i++){			data=ni_readw(ADC_FIFO_Data_Register);			data += devpriv->ai_offset[ async->cur_chan++ ];			async->cur_chan %= async->cmd.chanlist_len;			err &= comedi_buf_put(async, data);		}	}	if(err==0){		async->events |= COMEDI_CB_OVERFLOW;	}}static void ni_handle_fifo_half_full(comedi_device *dev){	int n;	comedi_subdevice *s=dev->subdevices+0;	/*	   if we got a fifo_half_full interrupt, we can transfer fifo/2	   samples without checking the empty flag.  It doesn't matter if	   we transfer the rest of the samples, the performance trade-off	   is minimal (checking empty flag for a few samples vs. having	   1% more interrupts.)  At really high speeds, it's better to	   ignore them.	*/	n=boardtype.ai_fifo_depth/2;	ni_ai_fifo_read(dev,s,n);}#endif#ifdef PCIDMAstatic int ni_ai_drain_dma(comedi_device *dev ){	struct mite_struct *mite = devpriv->mite;	int i;	static const int timeout = 10000;	for( i = 0; i < timeout; i++ )	{		if( ( win_in( AI_Status_1_Register ) & AI_FIFO_Empty_St ) &&			mite_bytes_in_transit( mite, AI_DMA_CHAN ) == 0 )			break;		comedi_udelay( 1 );	}	if( i == timeout )	{		rt_printk( "ni_mio_common: wait for dma drain timed out\n" );		return -1;	}	ni_sync_ai_dma( mite, dev );	return 0;}#endif/*   Empties the AI fifo*/static void ni_handle_fifo_dregs(comedi_device *dev){	comedi_subdevice *s=dev->subdevices+0;	comedi_async *async = s->async;	sampl_t data;	u32 dl;	int err = 1;	if(boardtype.reg_611x){		while((win_in(AI_Status_1_Register)&AI_FIFO_Empty_St) == 0){			dl=ni_readl(ADC_FIFO_Data_611x);			/* This may get the hi/lo data in the wrong order */			data = (dl>>16) + devpriv->ai_offset[async->cur_chan++];			async->cur_chan %= async->cmd.chanlist_len;			err &= comedi_buf_put(s->async, data);			data = (dl&0xffff) + devpriv->ai_offset[async->cur_chan++];			async->cur_chan %= async->cmd.chanlist_len;			err &= comedi_buf_put(s->async, data);		}	}else{		while((win_in(AI_Status_1_Register)&AI_FIFO_Empty_St) == 0){			data=ni_readw(ADC_FIFO_Data_Register);			data+=devpriv->ai_offset[async->cur_chan++];			async->cur_chan %= async->cmd.chanlist_len;			err &= comedi_buf_put(s->async, data);		}	}	if(err==0){		async->events |= COMEDI_CB_OVERFLOW;	}}static void get_last_sample_611x( comedi_device *dev ){	comedi_subdevice *s=dev->subdevices+0;	comedi_async *async = s->async;	sampl_t data;	u32 dl;	int err = 1;	if( boardtype.reg_611x == 0 ) return;	/* Check if there's a single sample stuck in the FIFO */	if(ni_readb(XXX_Status)&0x80){		dl=ni_readl(ADC_FIFO_Data_611x);		data = (dl&0xffff) + devpriv->ai_offset[async->cur_chan++];		async->cur_chan %= async->cmd.chanlist_len;		err &= comedi_buf_put(s->async, data);	}	if(err==0){		async->events |= COMEDI_CB_OVERFLOW;	}}static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s,	void *data, unsigned int num_bytes, unsigned int chan_index ){	comedi_async *async = s->async;	unsigned int i;	unsigned int length = num_bytes / sizeof( sampl_t );	sampl_t *array = data;	for(i = 0; i < length; i++)	{#ifdef PCIDMA		array[i] = __le16_to_cpu(array[i]);#endif		array[i] += devpriv->ai_offset[ chan_index ];		chan_index++;		chan_index %= async->cmd.chanlist_len;	}}#ifdef PCIDMA

⌨️ 快捷键说明

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