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

📄 das16.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	id:	0xc0	},	{	name:		"cio-das1401/12",	// cio-das1400_series.pdf	ai:		das16_ai_rinsn,	ai_nbits:	12,	ai_speed:	6250,	ai_pg:		das16_pg_1601,	ao:		NULL,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0,	i8254_offset:	0x0c,	size:		0x408,	id:	0xc0	},	{	name:		"cio-das1402/12",	// cio-das1400_series.pdf	ai:		das16_ai_rinsn,	ai_nbits:	12,	ai_speed:	6250,	ai_pg:		das16_pg_1602,	ao:		NULL,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0,	i8254_offset:	0x0c,	size:		0x408,	id:	0xc0	},	{	name:		"cio-das1402/16",	// cio-das1400_series.pdf	ai:		das16_ai_rinsn,	ai_nbits:	16,	ai_speed:	10000,	ai_pg:		das16_pg_1602,	ao:		NULL,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0,	i8254_offset:	0x0c,	size:		0x408,	id:	0xc0	},	{	name:		"cio-das1601/12",	// cio-das160x-1x.pdf	ai:		das16_ai_rinsn,	ai_nbits:	12,	ai_speed:	6250,	ai_pg:		das16_pg_1601,	ao:		das16_ao_winsn,	ao_nbits:	12,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0x400,	i8254_offset:	0x0c,	size:		0x408,	id:	0xc0	},	{	name:		"cio-das1602/12",	// cio-das160x-1x.pdf	ai:		das16_ai_rinsn,	ai_nbits:	12,	ai_speed:	10000,	ai_pg:		das16_pg_1602,	ao:		das16_ao_winsn,	ao_nbits:	12,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0x400,	i8254_offset:	0x0c,	size:		0x408,	id:	0xc0	},	{	name:		"cio-das1602/16",	// cio-das160x-1x.pdf	ai:		das16_ai_rinsn,	ai_nbits:	16,	ai_speed:	10000,	ai_pg:		das16_pg_1602,	ao:		das16_ao_winsn,	ao_nbits:	12,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0x400,	i8254_offset:	0x0c,	size:		0x408,	id:	0xc0	},	{	name:		"cio-das16/330",	// ?	ai:		das16_ai_rinsn,	ai_nbits:	12,	ai_speed:	3030,	ai_pg:		das16_pg_16jr,	ao:		NULL,	di:		das16_di_rbits,	do_:		das16_do_wbits,	i8255_offset:	0,	i8254_offset:	0x0c,	size:		0x14,	id:	0xf0	},#if 0	{	name:		"das16/330i",	// ?	},	{	name:		"das16/jr/ctr5", // ?	},	{	name:		"cio-das16/m1/16",	// cio-das16_m1_16.pdf, this board is a bit quirky, no dma	},#endif};#define n_das16_boards ((sizeof(das16_boards))/(sizeof(das16_board)))static int das16_attach(comedi_device *dev,comedi_devconfig *it);static int das16_detach(comedi_device *dev);static comedi_driver driver_das16={	driver_name:	"das16",	module:		THIS_MODULE,	attach:		das16_attach,	detach:		das16_detach,	board_name:	das16_boards,	num_names:	n_das16_boards,	offset:		sizeof(das16_boards[0]),};#define DAS16_TIMEOUT 1000static const int timer_period = HZ / 20 + 1;	// period for timer interrupt in jiffies (about 1/20 of a second)struct das16_private_struct{	unsigned int	ai_unipolar;	// unipolar flag	unsigned int	ai_singleended;	// single ended flag	unsigned int	clockbase;	// master clock speed in ns	volatile unsigned int	control_state;	// dma, interrupt and trigger control bits	volatile unsigned long	adc_byte_count;	// number of samples remaining	unsigned int divisor1;	// divisor dividing master clock to get conversion frequency	unsigned int divisor2;	// divisor dividing master clock to get conversion frequency	unsigned int dma_chan;	// dma channel	uint16_t *dma_buffer[2];	dma_addr_t dma_buffer_addr[2];	unsigned int current_buffer;	volatile unsigned int dma_transfer_size;	// target number of bytes to transfer per dma shot	// user-defined analog input and output ranges defined from config options	comedi_lrange *user_ai_range_table;	comedi_lrange *user_ao_range_table;	struct munge_info ai_munge_info;	struct timer_list timer;                // for timed interrupt	volatile unsigned int timer_running : 1;	volatile unsigned int timer_mode : 1;   // true if using timer mode};#define devpriv ((struct das16_private_struct *)(dev->private))#define thisboard ((struct das16_board_struct *)(dev->board_ptr))static int das16_cmd_test(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){	int err=0, tmp;	int gain, start_chan, i;	int mask;	/* make sure triggers are valid */	tmp=cmd->start_src;	cmd->start_src &= TRIG_NOW;	if(!cmd->start_src || tmp!=cmd->start_src)err++;	tmp=cmd->scan_begin_src;	mask = TRIG_FOLLOW;	// if board supports burst mode	if(thisboard->size > 0x400)		mask |= TRIG_TIMER | TRIG_EXT;	cmd->scan_begin_src &= mask;	if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;	tmp=cmd->convert_src;	mask = TRIG_TIMER | TRIG_EXT;	// if board supports burst mode	if(thisboard->size > 0x400)		mask |= TRIG_NOW;	cmd->convert_src &= mask;	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_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 */	if(cmd->scan_begin_src != TRIG_TIMER &&		cmd->scan_begin_src != TRIG_EXT &&		cmd->scan_begin_src != TRIG_FOLLOW) err++;	if(cmd->convert_src != TRIG_TIMER &&		cmd->convert_src != TRIG_EXT &&		cmd->convert_src != TRIG_NOW) err++;	if(cmd->stop_src != TRIG_NONE &&		cmd->stop_src != TRIG_COUNT) err++;	// make sure scan_begin_src and convert_src dont conflict	if(cmd->scan_begin_src == TRIG_FOLLOW &&		cmd->convert_src == TRIG_NOW) err++;	if(cmd->scan_begin_src != TRIG_FOLLOW &&		cmd->convert_src != TRIG_NOW) 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->scan_begin_src==TRIG_FOLLOW)	{		/* internal trigger */		if(cmd->scan_begin_arg!=0)		{			cmd->scan_begin_arg=0;			err++;		}	}	if(cmd->scan_end_arg != cmd->chanlist_len)	{		cmd->scan_end_arg = cmd->chanlist_len;		err++;	}	// check against maximum frequency	if(cmd->scan_begin_src == TRIG_TIMER)	{		if(cmd->scan_begin_arg < thisboard->ai_speed * cmd->chanlist_len)		{			cmd->scan_begin_arg = thisboard->ai_speed * cmd->chanlist_len;			err++;		}	}	if(cmd->convert_src == TRIG_TIMER)	{		if(cmd->convert_arg < thisboard->ai_speed)		{			cmd->convert_arg = thisboard->ai_speed;			err++;		}	}	if(cmd->stop_src == TRIG_NONE)	{		if(cmd->stop_arg != 0)		{			cmd->stop_arg = 0;			err++;		}	}	if(err)return 3;	// step 4: fix up arguments	if(cmd->scan_begin_src == TRIG_TIMER)	{		unsigned int tmp = cmd->scan_begin_arg;		// set divisors, correct timing arguments		i8253_cascade_ns_to_timer_2div(devpriv->clockbase,			&(devpriv->divisor1), &(devpriv->divisor2),			&(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK);		err += (tmp!=cmd->scan_begin_arg);	}	if(cmd->convert_src == TRIG_TIMER)	{		unsigned int tmp = cmd->convert_arg;		// set divisors, correct timing arguments		i8253_cascade_ns_to_timer_2div(devpriv->clockbase,			&(devpriv->divisor1), &(devpriv->divisor2),			&(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);		err += (tmp!=cmd->convert_arg);	}	if(err)return 4;	// check channel/gain list against card's limitations	if(cmd->chanlist){		gain = CR_RANGE(cmd->chanlist[0]);		start_chan = CR_CHAN(cmd->chanlist[0]);		for(i = 1; i < cmd->chanlist_len; i++)		{			if(CR_CHAN(cmd->chanlist[i]) != (start_chan + i) % s->n_chan)			{				comedi_error(dev, "entries in chanlist must be consecutive channels, counting upwards\n");				err++;			}			if(CR_RANGE(cmd->chanlist[i]) != gain)			{				comedi_error(dev, "entries in chanlist must all have the same gain\n");				err++;			}		}	}	if(err)return 5;	return 0;}static int das16_cmd_exec(comedi_device *dev,comedi_subdevice *s){	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	unsigned int byte;	unsigned long flags;	int range;	if(devpriv->dma_chan == 0 || (dev->irq == 0 && devpriv->timer_mode == 0))	{		comedi_error(dev, "irq (or use of 'timer mode') dma required to execute comedi_cmd");		return -1;	}	if(cmd->flags & TRIG_RT)	{		comedi_error(dev, "isa dma transfers cannot be performed with TRIG_RT, aborting");		return -1;	}	devpriv->adc_byte_count = cmd->stop_arg * cmd->chanlist_len * sizeof( uint16_t );	// disable conversions for das1600 mode	if(thisboard->size > 0x400)	{		outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV);	}	// set scan limits	byte = CR_CHAN(cmd->chanlist[0]);	byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;	outb(byte, dev->iobase + DAS16_MUX);	/* set gain (this is also burst rate register but according to	 * computer boards manual, burst rate does nothing, even on keithley cards) */	if(thisboard->ai_pg != das16_pg_none){		range = CR_RANGE(cmd->chanlist[0]);		outb((das16_gainlists[thisboard->ai_pg])[range],			dev->iobase+DAS16_GAIN);	}	/* set counter mode and counts */	cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);	DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg);	/* enable counters */	byte = 0;	/* Enable burst mode if appropriate. */	if(thisboard->size > 0x400)	{		if(cmd->convert_src == TRIG_NOW)		{			outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST);			// set burst length			byte |= BURST_LEN_BITS(cmd->chanlist_len - 1);		}else		{			outb(0, dev->iobase + DAS1600_BURST);		}	}	outb(byte, dev->iobase + DAS16_PACER);	// set up dma transfer	flags = claim_dma_lock();	disable_dma(devpriv->dma_chan);	/* clear flip-flop to make sure 2-byte registers for	 * count and address get set correctly */	clear_dma_ff(devpriv->dma_chan);	init_munge_info( &devpriv->ai_munge_info );	devpriv->current_buffer = 0;	set_dma_addr( devpriv->dma_chan,		devpriv->dma_buffer_addr[ devpriv->current_buffer ] );	// set appropriate size of transfer	devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd);	set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);	enable_dma(devpriv->dma_chan);	release_dma_lock(flags);	// set up interrupt	if( devpriv->timer_mode )	{		devpriv->timer_running = 1;		devpriv->timer.expires = jiffies + timer_period;		add_timer(&devpriv->timer);		devpriv->control_state &= ~DAS16_INTE;	}else	{		/* clear interrupt bit */		outb(0x00, dev->iobase + DAS16_STATUS);		/* enable interrupts */		devpriv->control_state |= DAS16_INTE;	}	devpriv->control_state |= DMA_ENABLE;	devpriv->control_state &= ~PACING_MASK;	if(cmd->convert_src == TRIG_EXT)		devpriv->control_state |= EXT_PACER;	else		devpriv->control_state |= INT_PACER;	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);	/* Enable conversions if using das1600 mode */	if(thisboard->size > 0x400)	{		outb(0, dev->iobase + DAS1600_CONV);	}	return 0;}static int das16_cancel(comedi_device *dev, comedi_subdevice *s){	unsigned long flags;	comedi_spin_lock_irqsave( &dev->spinlock, flags );	/* disable interrupts, dma and pacer clocked conversions */	devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE;	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);	if(devpriv->dma_chan)		disable_dma(devpriv->dma_chan);	// disable SW timer	if( devpriv->timer_mode && devpriv->timer_running )	{		devpriv->timer_running = 0;		del_timer(&devpriv->timer);	}	/* disable burst mode */	if(thisboard->size > 0x400)	{		outb(0, dev->iobase + DAS1600_BURST);	}	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	return 0;}static void das16_reset(comedi_device *dev){	outb(0, dev->iobase + DAS16_STATUS);	outb(0, dev->iobase + DAS16_CONTROL);	outb(0, dev->iobase + DAS16_PACER);	outb(0, dev->iobase + DAS16_CNTR_CONTROL);}static int das16_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){	int i,n;	int range;	int chan;	int msb,lsb;	// disable interrupts and pacing	devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK;	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);	/* set multiplexer */	chan = CR_CHAN(insn->chanspec);	chan |= CR_CHAN(insn->chanspec) << 4;	outb(chan, dev->iobase + DAS16_MUX);	/* set gain */	if(thisboard->ai_pg != das16_pg_none)	{		range = CR_RANGE(insn->chanspec);		outb((das16_gainlists[thisboard->ai_pg])[range],			dev->iobase+DAS16_GAIN);	}	for(n = 0; n < insn->n; n++)	{		/* trigger conversion */		outb_p(0, dev->iobase + DAS16_TRIG);		for(i = 0; i < DAS16_TIMEOUT; i++)		{			if(!(inb(dev->iobase + DAS16_STATUS) & BUSY))				break;		}		if(i == DAS16_TIMEOUT)		{			rt_printk("das16: timeout\n");			return -ETIME;		}		msb = inb(dev->iobase + DAS16_AI_MSB);		lsb = inb(dev->iobase + DAS16_AI_LSB);		if(thisboard->ai_nbits == 12){			data[n] = ((lsb >> 4) & 0xf) | (msb << 4);		}else{			data[n] = lsb | (msb << 8);		}	}	return n;}static int das16_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){	lsampl_t bits;	bits = inb(dev->iobase + DAS16_DIO) & 0xf;	data[1] = bits;	data[0] = 0;	return 2;}static int das16_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){	lsampl_t wbits;	// only set bits that have been masked	data[0] &= 0xf;	wbits = s->state;	// zero bits that have been masked	wbits &= ~data[0];	// set masked bits	wbits |= data[0] & data[1];	s->state = wbits;	data[1] = wbits;	outb(s->state, dev->iobase + DAS16_DIO);	return 2;}static int das16_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){	int i;	int lsb,msb;	int chan;	chan = CR_CHAN(insn->chanspec);	for(i = 0; i < insn->n; i++)	{		if(thisboard->ao_nbits == 12)		{			lsb = (data[i] << 4) & 0xff;			msb = (data[i] >> 4) & 0xff;		}else		{			lsb = data[i] & 0xff;			msb = (data[i] >> 8) & 0xff;		}		outb(lsb,dev->iobase+DAS16_AO_LSB(chan));		outb(msb,dev->iobase+DAS16_AO_MSB(chan));	}	return i;}static void das16_dma_interrupt(int irq, void *d, struct pt_regs *regs){	int status;	comedi_device *dev = d;	status = inb(dev->iobase + DAS16_STATUS);	if((status & DAS16_INT ) == 0)	{		DEBUG_PRINT( "spurious interrupt\n" );		return;	}	/* clear interrupt */	outb(0x00, dev->iobase + DAS16_STATUS);	das16_interrupt(dev);}static void das16_timer_interrupt(unsigned long arg){	comedi_device *dev = (comedi_device*) arg;	das16_interrupt(dev);

⌨️ 快捷键说明

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