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

📄 das800.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	int irq = it->options[1];	unsigned long irq_flags;	int board;	printk("comedi%d: das800: io 0x%x", dev->minor, iobase);	if(irq)	{		printk(", irq %i", irq);	}	printk("\n");	/* allocate and initialize dev->private */	if(alloc_private(dev, sizeof(das800_private)) < 0)		return -ENOMEM;	if(iobase == 0)	{		printk("io base address required for das800\n");		return -EINVAL;	}	/* check if io addresses are available */	if(check_region(iobase, DAS800_SIZE) < 0)	{		printk("I/O port conflict\n");		return -EIO;	}	request_region(iobase, DAS800_SIZE, "das800");	dev->iobase = iobase;	board = das800_probe(dev);	if(board < 0)	{		printk("unable to determine board type\n");		return -ENODEV;	}	dev->board_ptr = das800_boards + board;	/* grab our IRQ */	if(irq == 1 || irq > 7 || irq < 0)	{		printk("irq out of range\n");		return -EINVAL;	}	if(irq)	{		if(comedi_request_irq( irq, das800_interrupt, 0, "das800", dev ))		{			printk( "unable to allocate irq %d\n", irq);			return -EINVAL;		}	}	dev->irq = irq;	dev->board_name = thisboard->name;	if(alloc_subdevices(dev, 3) < 0)		return -ENOMEM;	/* analog input subdevice */	s = dev->subdevices + 0;	dev->read_subdev = s;	s->type = COMEDI_SUBD_AI;	s->subdev_flags = SDF_READABLE | SDF_GROUND;	s->n_chan = 8;	s->len_chanlist = 8;	s->maxdata = (1 << thisboard->resolution) - 1;	s->range_table = thisboard->ai_range;	s->do_cmd = das800_ai_do_cmd;	s->do_cmdtest = das800_ai_do_cmdtest;	s->insn_read = das800_ai_rinsn;	s->cancel = das800_cancel;	/* di */	s = dev->subdevices + 1;	s->type=COMEDI_SUBD_DI;	s->subdev_flags = SDF_READABLE;	s->n_chan = 3;	s->maxdata = 1;	s->range_table = &range_digital;	s->insn_bits = das800_di_rbits;	/* do */	s = dev->subdevices + 2;	s->type=COMEDI_SUBD_DO;	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;	s->n_chan = 4;	s->maxdata = 1;	s->range_table = &range_digital;	s->insn_bits = das800_do_wbits;	disable_das800(dev);	/* initialize digital out channels */	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */	outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	return 0;};static int das800_detach(comedi_device *dev){	printk("comedi%d: das800: remove\n", dev->minor);	/* only free stuff if it has been allocated by _attach */	if(dev->iobase)		release_region(dev->iobase, DAS800_SIZE);	if(dev->irq)		comedi_free_irq(dev->irq, dev);	return 0;};static int das800_cancel(comedi_device *dev, comedi_subdevice *s){	devpriv->forever = 0;	devpriv->count = 0;	disable_das800(dev);	return 0;}/* enable_das800 makes the card start taking hardware triggered conversions */static void enable_das800(comedi_device *dev){	unsigned long irq_flags;	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	// enable fifo-half full interrupts for cio-das802/16	if(thisboard->resolution == 16)		outb(CIO_ENHF, dev->iobase + DAS800_GAIN);	outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be conversion control register */	outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL);	/* enable hardware triggering */	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */	outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);	/* enable card's interrupt */	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);}/* disable_das800 stops hardware triggered conversions */static void disable_das800(comedi_device *dev){	unsigned long irq_flags;	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be conversion control register */	outb(0x0, dev->iobase + DAS800_CONV_CONTROL);	/* disable hardware triggering of conversions */	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);}static int das800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){	int err = 0;	int tmp;	int gain, startChan;	int i;	/* 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;	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_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->start_src != TRIG_NOW &&		cmd->start_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) 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++;	}	if(cmd->stop_src == TRIG_COUNT)	{		if(!cmd->stop_arg)		{			cmd->stop_arg = 1;			err++;		}	} else	{ /* TRIG_NONE */		if(cmd->stop_arg != 0)		{			cmd->stop_arg = 0;			err++;		}	}	if(err)return 3;	/* step 4: fix up any arguments */	if(cmd->convert_src == TRIG_TIMER)	{		tmp = 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 != cmd->convert_arg) err++;	}	if(err)return 4;	// check channel/gain list against card's limitations	if(cmd->chanlist)	{		gain = CR_RANGE(cmd->chanlist[0]);		startChan = CR_CHAN(cmd->chanlist[0]);		for(i = 1; i < cmd->chanlist_len; i++)		{			if(CR_CHAN(cmd->chanlist[i]) != (startChan + i) % N_CHAN_AI)			{				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 das800_ai_do_cmd(comedi_device *dev, comedi_subdevice *s){	int startChan, endChan, scan, gain;	int conv_bits;	unsigned long irq_flags;	comedi_async *async = s->async;	if(!dev->irq)	{		comedi_error(dev, "no irq assigned for das-800, cannot do hardware conversions");		return -1;	}	disable_das800(dev);	/* set channel scan limits */	startChan = CR_CHAN(async->cmd.chanlist[0]);	endChan = (startChan + async->cmd.chanlist_len - 1) % 8;	scan = (endChan << 3) | startChan;	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN);	/* select base address + 2 to be scan limits register */	outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	/* set gain */	gain = CR_RANGE(async->cmd.chanlist[0]);	if( thisboard->resolution == 12 && gain > 0)		gain += 0x7;	gain &= 0xf;	outb(gain, dev->iobase + DAS800_GAIN);	switch(async->cmd.stop_src)	{		case TRIG_COUNT:			devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;			devpriv->forever = 0;			break;		case TRIG_NONE:			devpriv->forever = 1;			devpriv->count = 0;			break;		default :			break;	}	/* enable auto channel scan, send interrupts on end of conversion	 * and set clock source to internal or external	 */	conv_bits = 0;	conv_bits |= EACS | IEOC;	if(async->cmd.start_src == TRIG_EXT)		conv_bits |= DTEN;	switch(async->cmd.convert_src)	{		case TRIG_TIMER:			conv_bits |= CASC | ITE;			/* set conversion frequency */			i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), &(async->cmd.convert_arg), async->cmd.flags & TRIG_ROUND_MASK);			if(das800_set_frequency(dev) < 0)			{				comedi_error(dev, "Error setting up counters");				return -1;			}			break;		case TRIG_EXT:			break;		default:			break;	}	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(CONV_CONTROL, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be conversion control register */	outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	async->events = 0;	enable_das800(dev);	return 0;}static int das800_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ 	int i, n;	int chan;	int range;	int lsb, msb;	int timeout = 1000;	unsigned long irq_flags;	disable_das800(dev);	/* disable hardware conversions (enables software conversions) */	/* set multiplexer */	chan = CR_CHAN(insn->chanspec);	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */	outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	/* set gain / range */	range = CR_RANGE(insn->chanspec);	if(thisboard->resolution == 12 && range)		range += 0x7;	range &= 0xf;	outb(range, dev->iobase + DAS800_GAIN);	comedi_udelay(5);	for(n = 0; n < insn->n; n++)	{		/* trigger conversion */		outb_p(0, dev->iobase + DAS800_MSB);		for(i = 0; i < timeout; i++)		{			if(!(inb(dev->iobase + DAS800_STATUS) & BUSY))				break;		}		if(i == timeout)		{			comedi_error(dev, "timeout");			return -ETIME;		}		lsb = inb(dev->iobase + DAS800_LSB);		msb = inb(dev->iobase + DAS800_MSB);		if(thisboard->resolution == 12)		{			data[n] = (lsb >> 4) & 0xff;			data[n] |= (msb << 4);		}else		{			data[n] = (msb << 8) | lsb;		}	}	return n;}static int das800_di_rbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){	lsampl_t bits;	bits = inb(dev->iobase + DAS800_STATUS) >> 4;	bits &= 0x7;	data[1] = bits;	data[0] = 0;	return 2;}static int das800_do_wbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){	int wbits;	unsigned long irq_flags;	// only set bits that have been masked	data[0] &= 0xf;	wbits = devpriv->do_bits >> 4;	wbits &= ~data[0];	wbits |= data[0] & data[1];	devpriv->do_bits = wbits << 4;	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(CONTROL1, dev->iobase + DAS800_GAIN);	/* select dev->iobase + 2 to be control register 1 */	outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	data[1] = wbits;	return 2;}/* loads counters with divisor1, divisor2 from private structure */static int das800_set_frequency(comedi_device *dev){	int err = 0;	if(i8254_load(dev->iobase + DAS800_8254, 1, devpriv->divisor1, 2)) err++;	if(i8254_load(dev->iobase + DAS800_8254, 2, devpriv->divisor2, 2)) err++;	if(err)		return -1;	return 0;}

⌨️ 快捷键说明

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