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

📄 pcl812.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (devpriv->ai_dma) { interrupt_pcl812_ai_dma(irq, d, regs); }			else { interrupt_pcl812_ai_int(irq, d, regs); };}/*==============================================================================*/static int pcl812_ai_poll(comedi_device *dev,comedi_subdevice *s){	unsigned long flags;        unsigned int top1,top2,i;	if (!devpriv->ai_dma) return 0; // poll is valid only for DMA transfer	comedi_spin_lock_irqsave(&dev->spinlock,flags);	for (i=0; i<10; i++) {		top1=get_dma_residue(devpriv->ai_dma); // where is now DMA		top2=get_dma_residue(devpriv->ai_dma);		if (top1==top2) break;	}	if (top1!=top2) {		comedi_spin_unlock_irqrestore(&dev->spinlock,flags);		return 0;	}	top1=devpriv->dmabytestomove[1-devpriv->next_dma_buf]-top1; // where is now DMA in buffer	top1>>=1; // sample position	top2=top1-devpriv->ai_poll_ptr;	if (top2<1) { // no new samples		comedi_spin_unlock_irqrestore(&dev->spinlock,flags);		return 0;	}	transfer_from_dma_buf(dev, s, (void *)devpriv->dmabuf[1-devpriv->next_dma_buf],				devpriv->ai_poll_ptr, top2);	devpriv->ai_poll_ptr=top1; // new buffer position	comedi_spin_unlock_irqrestore(&dev->spinlock,flags);	return s->async->buf_write_count-s->async->buf_read_count;}/*==============================================================================*/static void setup_range_channel(comedi_device * dev, comedi_subdevice * s, 	unsigned int rangechan, char wait){	unsigned char chan_reg=CR_CHAN(rangechan); // normal board	unsigned char gain_reg=CR_RANGE(rangechan)+devpriv->range_correction; // gain index		if ((chan_reg==devpriv->old_chan_reg)&&(gain_reg==devpriv->old_gain_reg)) 		return;	// we can return, no change			devpriv->old_chan_reg=chan_reg;	devpriv->old_gain_reg=gain_reg;		if (devpriv->use_MPC) {		if (devpriv->use_diff) {			chan_reg=chan_reg | 0x30; // DIFF inputs 		} else {			if (chan_reg&0x80) {				chan_reg=chan_reg | 0x20; // SE inputs 8-15			} else {				chan_reg=chan_reg | 0x10; // SE inputs 0-7			}		}	}		outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */	outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */        if (wait) {		comedi_udelay(devpriv->max_812_ai_mode0_rangewait); // XXX this depends on selected range and can be very long for some high gain ranges!        }}/*==============================================================================*/static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) {#ifdef PCL812_EXTDEBUG	rt_printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n",mode,divisor1,divisor2);#endif        outb(0xb4, dev->iobase + PCL812_CTRCTL);        outb(0x74, dev->iobase + PCL812_CTRCTL);        comedi_udelay(1);          if (mode==1) {		outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);		outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);		outb(divisor1  & 0xff, dev->iobase + PCL812_CTR1);		outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);        }#ifdef PCL812_EXTDEBUG	rt_printk("pcl812 EDBG: END: start_pacer(...)\n");#endif}/* ==============================================================================*/static void free_resources(comedi_device * dev){	if (dev->private) {		if (devpriv->dmabuf[0])			free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);		if (devpriv->dmabuf[1])			free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);		if (devpriv->dma)			free_dma(devpriv->dma);	}	if (dev->irq)		comedi_free_irq(dev->irq, dev);	if (dev->iobase)		release_region(dev->iobase, this_board->io_range);}/* ==============================================================================*/static int pcl812_ai_cancel(comedi_device * dev, comedi_subdevice * s){#ifdef PCL812_EXTDEBUG	rt_printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");#endif	if (devpriv->ai_dma) disable_dma(devpriv->dma);	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */	outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE);	/* Stop A/D */	start_pacer(dev,-1,0,0);		// stop 8254	outb(0, dev->iobase + PCL812_CLRINT);	/* clear INT request */#ifdef PCL812_EXTDEBUG	rt_printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n");#endif	return 0;}/* ==============================================================================*/static void pcl812_reset(comedi_device * dev){#ifdef PCL812_EXTDEBUG	rt_printk("pcl812 EDBG: BGN: pcl812_reset(...)\n");#endif	outb(0, dev->iobase + PCL812_MUX);	outb(0+devpriv->range_correction, dev->iobase + PCL812_GAIN);	devpriv->old_chan_reg=-1;	// invalidate chain/gain memory	devpriv->old_gain_reg=-1;	switch (this_board->board_type) {	case boardPCL812PG:	case boardPCL812:	case boardACL8112:	case boardACL8216:		outb(0, dev->iobase + PCL812_DA2_LO);		outb(0, dev->iobase + PCL812_DA2_HI);	case boardA821:		outb(0, dev->iobase + PCL812_DA1_LO);		outb(0, dev->iobase + PCL812_DA1_HI);		start_pacer(dev,-1,0,0);		// stop 8254		outb(0, dev->iobase + PCL812_DO_HI);		outb(0, dev->iobase + PCL812_DO_LO);		outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE);		outb(0, dev->iobase + PCL812_CLRINT);		break;	case boardPCL813B:	case boardPCL813:	case boardISO813:	case boardACL8113:		comedi_udelay(5);		break;	}	comedi_udelay(5);#ifdef PCL812_EXTDEBUG	rt_printk("pcl812 EDBG: END: pcl812_reset(...)\n");#endif}/*==============================================================================*/static int pcl812_attach(comedi_device * dev, comedi_devconfig * it){	int ret,subdev;	int iobase;	int irq;	int dma;	unsigned long pages;	comedi_subdevice *s;	int n_subdevices;	iobase = it->options[0];	printk("comedi%d: pcl812:  board=%s, ioport=0x%03x", dev->minor,		this_board->name, iobase);	if (check_region(iobase, this_board->io_range) < 0) {		printk("I/O port conflict\n");		return -EIO;	}	request_region(iobase, this_board->io_range, "pcl812");	dev->iobase = iobase;	if ((ret = alloc_private(dev, sizeof(pcl812_private))) < 0) {		free_resources(dev);		return ret;	/* Can't alloc mem */	}	dev->board_name = this_board->name;	irq = 0;	if (this_board->IRQbits != 0) {	/* board support IRQ */		irq = it->options[1];		if (irq) {	/* we want to use IRQ */			if (((1 << irq) & this_board->IRQbits) == 0) {				printk(", IRQ %d is out of allowed range, DISABLING IT", irq);				irq = 0;	/* Bad IRQ */			} else {				if (comedi_request_irq(irq, interrupt_pcl812, 0, "pcl812", dev)) {					printk(", unable to allocate IRQ %d, DISABLING IT", irq);					irq = 0;	/* Can't use IRQ */				} else {					printk(", irq=%d", irq);				}			}		}	}	dev->irq = irq;	dma = 0;	devpriv->dma = dma;	if (!dev->irq)		goto no_dma;	/* if we haven't IRQ, we can't use DMA */	if (this_board->DMAbits != 0) {	/* board support DMA */		dma = it->options[2];		if (((1 << dma) & this_board->DMAbits) == 0) {			printk(", DMA is out of allowed range, FAIL!\n");			return -EINVAL;	/* Bad DMA */		}		ret = request_dma(dma, "pcl812");		if (ret) {			printk(", unable to allocate DMA %d, FAIL!\n", dma);			return -EBUSY;	/* DMA isn't free */		}		devpriv->dma = dma;		printk(", dma=%d", dma);		pages = 1;	/* we want 8KB */		devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);		if (!devpriv->dmabuf[0]) {			printk(", unable to allocate DMA buffer, FAIL!\n");			/* maybe experiment with try_to_free_pages() will help .... */			free_resources(dev);			return -EBUSY;	/* no buffer :-( */		}		devpriv->dmapages[0] = pages;		devpriv->hwdmaptr[0] = virt_to_bus((void *) devpriv->dmabuf[0]);		devpriv->hwdmasize[0] = PAGE_SIZE * (1<<pages);		devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);		if (!devpriv->dmabuf[1]) {			printk(", unable to allocate DMA buffer, FAIL!\n");			free_resources(dev);			return -EBUSY;		}		devpriv->dmapages[1] = pages;		devpriv->hwdmaptr[1] = virt_to_bus((void *) devpriv->dmabuf[1]);		devpriv->hwdmasize[1] = PAGE_SIZE * (1<<pages);	}      no_dma:	n_subdevices=0;	if (this_board->n_aichan > 0) n_subdevices++;	if (this_board->n_aochan > 0) n_subdevices++;	if (this_board->n_dichan > 0) n_subdevices++;	if (this_board->n_dochan > 0) n_subdevices++;	if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) {		free_resources(dev);		return ret;	}	subdev=0;	/* analog input */	if (this_board->n_aichan>0) {		s = dev->subdevices + subdev;		dev->read_subdev = s;		s->type = COMEDI_SUBD_AI;		s->subdev_flags = SDF_READABLE;		switch (this_board->board_type) {		case boardA821:			if (it->options[2] == 1) {				s->n_chan = this_board->n_aichan_diff;				s->subdev_flags |= SDF_DIFF;				devpriv->use_diff=1;			} else {				s->n_chan = this_board->n_aichan;				s->subdev_flags |= SDF_GROUND;			}			break;				case boardACL8112:		case boardACL8216:			if (it->options[4] == 1) {				s->n_chan = this_board->n_aichan_diff;				s->subdev_flags |= SDF_DIFF;				devpriv->use_diff=1;			} else {				s->n_chan = this_board->n_aichan;				s->subdev_flags |= SDF_GROUND;			}			break;				default:			s->n_chan = this_board->n_aichan;			s->subdev_flags |= SDF_GROUND;			break;				}		s->maxdata = this_board->ai_maxdata;		s->len_chanlist = MAX_CHANLIST_LEN;		s->range_table = this_board->rangelist_ai;		if (this_board->board_type==boardACL8216) {			s->insn_read = acl8216_ai_insn_read;		} else {			s->insn_read = pcl812_ai_insn_read;		}		devpriv->use_MPC = this_board->haveMPC508;		s->cancel = pcl812_ai_cancel;		if (dev->irq) {			s->do_cmdtest = pcl812_ai_cmdtest;			s->do_cmd = pcl812_ai_cmd;			s->poll = pcl812_ai_poll;		}		switch (this_board->board_type) {		case boardPCL812PG:			if (it->options[4] == 1)				s->range_table = &range_pcl812pg2_ai;			break;		case boardPCL812:			switch (it->options[4]) {			case 0:	s->range_table = &range_bipolar10; break;			case 1:	s->range_table = &range_bipolar5; break;			case 2:	s->range_table = &range_bipolar2_5; break;			case 3:	s->range_table = &range812_bipolar1_25; break;			case 4:	s->range_table = &range812_bipolar0_625; break;			case 5:	s->range_table = &range812_bipolar0_3125; break;			default:				s->range_table = &range_bipolar10; break;				printk(", incorrect range number %d, changing to 0 (+/-10V)", it->options[4]);				break;			}			break;			break;		case boardPCL813B:			if (it->options[1] == 1)				s->range_table = &range_pcl813b2_ai;			break;		case boardISO813:			switch (it->options[1]) {			case 0:	s->range_table = &range_iso813_1_ai; break;			case 1:	s->range_table = &range_iso813_1_2_ai; break;			case 2:	s->range_table = &range_iso813_2_ai; devpriv->range_correction=1; break;			case 3:	s->range_table = &range_iso813_2_2_ai; devpriv->range_correction=1; break;			default:				s->range_table = &range_iso813_1_ai; break;				printk(", incorrect range number %d, changing to 0 ", it->options[1]);				break;			}			break;		case boardACL8113:			switch (it->options[1]) {			case 0:	s->range_table = &range_acl8113_1_ai; break;			case 1:	s->range_table = &range_acl8113_1_2_ai; break;			case 2:	s->range_table = &range_acl8113_2_ai; devpriv->range_correction=1; break;			case 3:	s->range_table = &range_acl8113_2_2_ai; devpriv->range_correction=1; break;			default:				s->range_table = &range_acl8113_1_ai; break;				printk(", incorrect range number %d, changing to 0 ", it->options[1]);				break;			}			break;		}		subdev++;	}	/* analog output */	if (this_board->n_aochan>0) {		s = dev->subdevices + subdev;		s->type = COMEDI_SUBD_AO;		s->subdev_flags = SDF_WRITABLE|SDF_GROUND;		s->n_chan = this_board->n_aochan;		s->maxdata = 0xfff;		s->len_chanlist = 1;		s->range_table = this_board->rangelist_ao;		s->insn_read = pcl812_ao_insn_read;		s->insn_write = pcl812_ao_insn_write;		switch (this_board->board_type) {		case boardA821:			if (it->options[3] == 1)				s->range_table = &range_unipolar10;			break;		case boardPCL812:		case boardACL8112:		case boardPCL812PG:		case boardACL8216:			if (it->options[5] == 1)				s->range_table = &range_unipolar10;			if (it->options[5] == 2)				s->range_table = &range_unknown;			break;		}		subdev++;	}	/* digital input */	if (this_board->n_dichan>0) {		s = dev->subdevices + subdev;		s->type = COMEDI_SUBD_DI;		s->subdev_flags = SDF_READABLE;		s->n_chan = this_board->n_dichan;		s->maxdata = 1;		s->len_chanlist = this_board->n_dichan;		s->range_table = &range_digital;		s->insn_bits = pcl812_di_insn_bits;		subdev++;	}	/* digital output */	if (this_board->n_dochan>0) {		s = dev->subdevices + subdev;		s->type = COMEDI_SUBD_DO;		s->subdev_flags = SDF_WRITABLE;		s->n_chan = this_board->n_dochan;		s->maxdata = 1;		s->len_chanlist = this_board->n_dochan;		s->range_table = &range_digital;		s->insn_bits = pcl812_do_insn_bits;		subdev++;	}	switch (this_board->board_type) {	case boardACL8216:		devpriv->ai_is16b=1;	case boardPCL812PG:	case boardPCL812:	case boardACL8112:		devpriv->max_812_ai_mode0_rangewait = 1;		if (it->options[3] > 0) devpriv->use_ext_trg=1; // we use external trigger	case boardA821:		devpriv->max_812_ai_mode0_rangewait = 1;		devpriv->mode_reg_int=(irq<<4) & 0xf0;		break;	case boardPCL813B:	case boardPCL813:	case boardISO813:	case boardACL8113:		devpriv->max_812_ai_mode0_rangewait = 5;	/* maybe there must by greatest timeout */		break;	}		printk("\n");	devpriv->valid=1;	pcl812_reset(dev);	return 0;}/*============================================================================== */static int pcl812_detach(comedi_device * dev){#ifdef PCL812_EXTDEBUG	rt_printk("comedi%d: pcl812: remove\n", dev->minor);#endif	free_resources(dev);	return 0;}

⌨️ 快捷键说明

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