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

📄 das1800.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	return s->async->buf_write_count - s->async->buf_read_count;}static void das1800_interrupt(int irq, void *d, struct pt_regs *regs){	comedi_device *dev = d;	unsigned int status;	if(dev->attached == 0)	{		comedi_error(dev, "premature interrupt");		return;	}	/* Prevent race with das1800_ai_poll() on multi processor systems.	 * Also protects indirect addressing in das1800_ai_handler */	spin_lock(&dev->spinlock);	status = inb(dev->iobase + DAS1800_STATUS);	/* if interrupt was not caused by das-1800 */	if(!(status & INT))	{		spin_unlock(&dev->spinlock);		return;	}	/* clear the interrupt status bit INT*/	outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS);	// handle interrupt	das1800_ai_handler(dev);	spin_unlock(&dev->spinlock);}// the guts of the interrupt handler, that is shared with das1800_ai_pollstatic void das1800_ai_handler(comedi_device *dev){	comedi_subdevice *s = dev->subdevices + 0;	/* analog input subdevice */	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	unsigned int status = inb(dev->iobase + DAS1800_STATUS);	async->events = 0;	// select adc for base address + 0	outb(ADC, dev->iobase + DAS1800_SELECT);	// dma buffer full	if(devpriv->irq_dma_bits & DMA_ENABLED)	{		// look for data from dma transfer even if dma terminal count hasn't happened yet		das1800_handle_dma(dev, s, status);	}else if(status & FHF)	{	// if fifo half full		das1800_handle_fifo_half_full(dev, s);	}else if(status & FNE)	{	// if fifo not empty		das1800_handle_fifo_not_empty(dev, s);	}	async->events |= COMEDI_CB_BLOCK;	/* if the card's fifo has overflowed */	if(status & OVF)	{		// clear OVF interrupt bit		outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS);		comedi_error(dev, "DAS1800 FIFO overflow");		das1800_cancel(dev, s);		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;		comedi_event(dev, s, async->events);		return;	}	// stop taking data if appropriate	/* stop_src TRIG_EXT */	if(status & CT0TC)	{		// clear CT0TC interrupt bit		outb(CLEAR_INTR_MASK & ~CT0TC, dev->iobase + DAS1800_STATUS);		// make sure we get all remaining data from board before quitting		if(devpriv->irq_dma_bits & DMA_ENABLED)			das1800_flush_dma(dev, s);		else			das1800_handle_fifo_not_empty(dev, s);		das1800_cancel(dev, s);		/* disable hardware conversions */		async->events |= COMEDI_CB_EOA;	}else if(cmd->stop_src == TRIG_COUNT && devpriv->count == 0)	{ // stop_src TRIG_COUNT		das1800_cancel(dev, s);		/* disable hardware conversions */		async->events |= COMEDI_CB_EOA;	}	comedi_event(dev, s, async->events);	return;}static void das1800_handle_dma(comedi_device *dev, comedi_subdevice *s, unsigned int status){	unsigned long flags;	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;	flags = claim_dma_lock();	das1800_flush_dma_channel(dev, s, devpriv->dma_current, devpriv->dma_current_buf);	// re-enable  dma channel	set_dma_addr(devpriv->dma_current, virt_to_bus(devpriv->dma_current_buf));	set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size);	enable_dma(devpriv->dma_current);	release_dma_lock(flags);	if(status & DMATC)	{		// clear DMATC interrupt bit		outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS);		// switch dma channels for next time, if appropriate		if(dual_dma)		{			// read data from the other channel next time			if(devpriv->dma_current == devpriv->dma0)			{				devpriv->dma_current = devpriv->dma1;				devpriv->dma_current_buf = devpriv->ai_buf1;			}			else			{				devpriv->dma_current = devpriv->dma0;				devpriv->dma_current_buf = devpriv->ai_buf0;			}		}	}	return;}static inline uint16_t munge_bipolar_sample( const comedi_device *dev, uint16_t sample ){	sample += 1 << ( thisboard->resolution - 1 );	return sample;}static void munge_data( comedi_device *dev, uint16_t *array, unsigned int num_elements ){	unsigned int i;	int unipolar;	/* see if card is using a unipolar or bipolar range so we can munge data correctly */	unipolar = inb( dev->iobase + DAS1800_CONTROL_C ) & UB;	/* convert to unsigned type if we are in a bipolar mode */	if( !unipolar )	{		for( i = 0; i < num_elements; i++ )		{			array[i] = munge_bipolar_sample( dev, array[i] );		}	}}/* Utility function used by das1800_flush_dma() and das1800_handle_dma(). * Assumes dma lock is held */static void das1800_flush_dma_channel(comedi_device *dev, comedi_subdevice *s, unsigned int channel, uint16_t *buffer){	unsigned int num_bytes, num_samples;	comedi_cmd *cmd = &s->async->cmd;	disable_dma(channel);	/* clear flip-flop to make sure 2-byte registers	 * get set correctly */	clear_dma_ff(channel);	// figure out how many points to read	num_bytes = devpriv->dma_transfer_size - get_dma_residue( channel );	num_samples = num_bytes / sizeof( sampl_t );	/* if we only need some of the points */	if( cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples )		num_samples = devpriv->count;	munge_data( dev, buffer, num_samples );	cfc_write_array_to_buffer( s, buffer, num_bytes );	if(s->async->cmd.stop_src == TRIG_COUNT)		devpriv->count -= num_samples;	return;}/* flushes remaining data from board when external trigger has stopped aquisition * and we are using dma transfers */static void das1800_flush_dma(comedi_device *dev, comedi_subdevice *s){	unsigned long flags;	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;	flags = claim_dma_lock();	das1800_flush_dma_channel(dev, s, devpriv->dma_current, devpriv->dma_current_buf);	if(dual_dma)	{		// switch to other channel and flush it		if(devpriv->dma_current == devpriv->dma0)		{			devpriv->dma_current = devpriv->dma1;			devpriv->dma_current_buf = devpriv->ai_buf1;		}		else		{			devpriv->dma_current = devpriv->dma0;			devpriv->dma_current_buf = devpriv->ai_buf0;		}		das1800_flush_dma_channel(dev, s, devpriv->dma_current, devpriv->dma_current_buf);	}	release_dma_lock(flags);	// get any remaining samples in fifo	das1800_handle_fifo_not_empty(dev, s);	return;}static void das1800_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s){	int numPoints = 0;	/* number of points to read */	comedi_cmd *cmd = &s->async->cmd;	numPoints = FIFO_SIZE / 2;	/* if we only need some of the points */	if(cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints)		numPoints = devpriv->count;	insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints);	munge_data( dev, devpriv->ai_buf0, numPoints );	cfc_write_array_to_buffer( s, devpriv->ai_buf0, numPoints * sizeof( devpriv->ai_buf0[0] ) );	if( cmd->stop_src == TRIG_COUNT )		devpriv->count -= numPoints;	return;}static void das1800_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s){	sampl_t dpnt;	int unipolar;	comedi_cmd *cmd = &s->async->cmd;	unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;	while( inb( dev->iobase + DAS1800_STATUS ) & FNE )	{		if(cmd->stop_src == TRIG_COUNT && devpriv->count == 0)			break;		dpnt = inw( dev->iobase + DAS1800_FIFO );		/* convert to unsigned type if we are in a bipolar mode */		if(!unipolar);			dpnt = munge_bipolar_sample( dev, dpnt );		cfc_write_to_buffer( s, dpnt );		if(cmd->stop_src == TRIG_COUNT) devpriv->count--;	}	return;}static int das1800_cancel(comedi_device *dev, comedi_subdevice *s){	outb(0x0, dev->iobase + DAS1800_STATUS);	/* disable conversions */	outb(0x0, dev->iobase + DAS1800_CONTROL_B);	/* disable interrupts and dma */	outb(0x0, dev->iobase + DAS1800_CONTROL_A);	/* disable and clear fifo and stop triggering */	if(devpriv->dma0) disable_dma(devpriv->dma0);	if(devpriv->dma1) disable_dma(devpriv->dma1);	return 0;}/* test analog input cmd */static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){	int err = 0;	int tmp;	unsigned int tmp_arg;	int i;	int unipolar;	/* step 1: make sure trigger sources are trivially valid */	tmp = cmd->start_src;	cmd->start_src &= TRIG_NOW | TRIG_EXT;	if(!cmd->start_src || tmp != cmd->start_src) err++;	tmp = cmd->scan_begin_src;	cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;	if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++;	tmp = cmd->convert_src;	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;	if(!cmd->convert_src || tmp != cmd->convert_src) err++;	tmp = cmd->scan_end_src;	cmd->scan_end_src &= TRIG_COUNT;	if(!cmd->scan_end_src || tmp != cmd->scan_end_src) err++;	tmp=cmd->stop_src;	cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE;	if(!cmd->stop_src || tmp != cmd->stop_src) err++;	if(err) return 1;	/* step 2: make sure trigger sources are unique and mutually compatible */	// uniqueness check	if(cmd->start_src != TRIG_NOW &&		cmd->start_src != TRIG_EXT) err++;	if(cmd->scan_begin_src != TRIG_FOLLOW &&		cmd->scan_begin_src != TRIG_TIMER &&		cmd->scan_begin_src != TRIG_EXT) err++;	if(cmd->convert_src != TRIG_TIMER &&		cmd->convert_src != TRIG_EXT) err++;	if(cmd->stop_src != TRIG_COUNT &&		cmd->stop_src != TRIG_NONE &&		cmd->stop_src != TRIG_EXT) err++;	//compatibility check	if(cmd->scan_begin_src != TRIG_FOLLOW &&		cmd->convert_src != TRIG_TIMER) err++;	if(err) return 2;	/* step 3: make sure arguments are trivially compatible */	if(cmd->start_arg != 0)	{		cmd->start_arg = 0;		err++;	}	if(cmd->convert_src == TRIG_TIMER)	{		if(cmd->convert_arg < thisboard->ai_speed)		{			cmd->convert_arg = thisboard->ai_speed;			err++;		}	}	if(!cmd->chanlist_len)	{		cmd->chanlist_len = 1;		err++;	}	if(cmd->scan_end_arg != cmd->chanlist_len)	{		cmd->scan_end_arg = cmd->chanlist_len;		err++;	}	switch(cmd->stop_src)	{		case TRIG_COUNT:			if(!cmd->stop_arg)			{				cmd->stop_arg = 1;				err++;			}			break;		case TRIG_NONE:			if(cmd->stop_arg != 0)			{				cmd->stop_arg = 0;				err++;			}			break;		default:			break;	}	if(err) return 3;	/* step 4: fix up any arguments */	if(cmd->convert_src == TRIG_TIMER)	{		// if we are not in burst mode		if(cmd->scan_begin_src == TRIG_FOLLOW)		{			tmp_arg = cmd->convert_arg;			/* calculate counter values that give desired timing */			i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);			if(tmp_arg != cmd->convert_arg) err++;		}		// if we are in burst mode		else		{			// check that convert_arg is compatible			tmp_arg = cmd->convert_arg;			cmd->convert_arg = burst_convert_arg(cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);			if(tmp_arg != cmd->convert_arg) err++;			if(cmd->scan_begin_src == TRIG_TIMER)			{				// if scans are timed faster than conversion rate allows				if(cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg)				{					cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len;					err++;				}				tmp_arg = cmd->scan_begin_arg;				/* calculate counter values that give desired timing */				i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK);				if(tmp_arg != cmd->scan_begin_arg) err++;			}		}	}	if(err) return 4;	// make sure user is not trying to mix unipolar and bipolar ranges	if(cmd->chanlist)	{		unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR;		for(i = 1; i < cmd->chanlist_len; i++)		{			if(unipolar != (CR_RANGE(cmd->chanlist[i]) & UNIPOLAR))			{				comedi_error(dev, "unipolar and bipolar ranges cannot be mixed in the chanlist");				err++;				break;			}		}	}	if(err) return 5;	return 0;}/* analog input cmd interface */// first, some utility functions used in the main ai_do_cmd()// returns appropriate bits for control register a, depending on commandstatic int control_a_bits(comedi_cmd cmd){	int control_a;	control_a = FFEN;	//enable fifo	if(cmd.stop_src == TRIG_EXT)	{		control_a |= ATEN;	}	switch(cmd.start_src)	{

⌨️ 快捷键说明

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