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

📄 amplc_pci230.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		if(tmp!=cmd->convert_arg)err++;	}	if(err)return 4;	return 0;}static int pci230_ai_cmd(comedi_device *dev,comedi_subdevice *s){	int i, chan, range, diff;	unsigned int adccon, adcen, adcg;		/* Get the command. */	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	/* Calculate number of conversions required. */	if(cmd->stop_src == TRIG_COUNT) {		devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len;		devpriv->ai_stop = 0;	}	else {		/* TRIG_NONE, user calls cancel. */		devpriv->ai_count = 0;		devpriv->ai_stop = 1;	}		/* Steps;	 * - Disable ADC interrupts.	 * - Enable and reset FIFO, specify uni/bip, se/diff, and start conversion source to none.	 * - Set channel scan list.	 * - Set channel gains.	 * - Enable conversion complete interrupt.	 * - Set the counter timers to the specified sampling frequency.	 * - Enable FIFO, set FIFO interrupt trigger level, set start conversion source to counter 0. 	 */	/* Disable ADC interrupt. */	devpriv->ier &= ~PCI230_INT_ADC;	outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	if (CR_AREF(cmd->chanlist[0])==AREF_DIFF) {		/* Differential - all channels must be differential. */		diff = 1;		adccon = PCI230_ADC_IM_DIF;		}	else {		/* Single ended - all channels must be single-ended. */		diff = 0;		adccon = PCI230_ADC_IM_SE;		}	adccon |= PCI230_ADC_FIFO_RESET | PCI230_ADC_FIFO_EN;	adcg = 0;	adcen = 0;	/* If bit 2 of range unset, range is referring to bipolar element in range table */	range = CR_RANGE(cmd->chanlist[0]);	devpriv->ai_bipolar = !PCI230_TEST_BIT(range, 2);		if (devpriv->ai_bipolar) {		adccon |= PCI230_ADC_IR_BIP;		for (i = 0; i < cmd->chanlist_len; i++) {			chan = CR_CHAN(cmd->chanlist[i]);			range = CR_RANGE(cmd->chanlist[i]);			if (diff) {				adcg |= range<<(2*chan-2*chan%2);				adcen |= 3<<2*chan;			}			else {				adcg |= range<<(chan-chan%2);				adcen |= 1<<chan;			}		}	}	else {		adccon |= PCI230_ADC_IR_UNI;		for (i = 0; i < cmd->chanlist_len; i++) {			chan = CR_CHAN(cmd->chanlist[i]);			range = CR_RANGE(cmd->chanlist[i]);			if (diff) {				adcg |= ((range&(~4))+1)<<(2*chan-2*chan%2);				adcen |= 3<<2*chan;			}			else {				adcg |= ((range&(~4))+1)<<(chan-chan%2);				adcen |= 1<<chan;			}		}	}	/* Enable and reset FIFO, specify FIFO trigger level full, specify uni/bip, se/diff, and start conversion source to none. */	outw(adccon | PCI230_ADC_INT_FIFO_FULL | PCI230_ADC_TRIG_NONE, dev->iobase + PCI230_ADCCON);	/* Set channel scan list. */	outw(adcen, dev->iobase + PCI230_ADCEN);	/* Set channel gains. */	outw(adcg, dev->iobase + PCI230_ADCG);	/* Enable ADC (conversion complete) interrupt. */	devpriv->ier |= PCI230_INT_ADC;	outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	/* Set start conversion source. */	if(cmd->convert_src == TRIG_TIMER) {		/* Onboard counter/timer 0. */		adccon = adccon | PCI230_ADC_TRIG_Z2CT0;		/* Set the counter timers to the specified sampling frequency. */		pci230_z2_ct0(dev, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);	/* cmd->convert_arg is sampling period in ns */	}	else {		/* TRIG_EXT - external trigger. */		if (cmd->convert_arg) {			/* Trigger on +ve edge. */			adccon = adccon | PCI230_ADC_TRIG_EXTP;		}		else {			/* Trigger on -ve edge. */			adccon = adccon | PCI230_ADC_TRIG_EXTN;		}		}	/* Set FIFO interrupt trigger level. */	if(cmd->stop_src == TRIG_COUNT) {		if (devpriv->ai_count < 2048) {			adccon = adccon | PCI230_ADC_INT_FIFO_NEMPTY;		}		else {			adccon = adccon | PCI230_ADC_INT_FIFO_HALF;		}	}	else {		/* TRIG_NONE - trigger on half-full FIFO. */		adccon = adccon | PCI230_ADC_INT_FIFO_HALF;	}		outw(adccon, dev->iobase + PCI230_ADCCON);	return 0;}/* This function doesn't require a particular form, this is just * what happens to be used in some of the drivers.  It should * convert ns nanoseconds to a counter value suitable for programming * the device.  Also, it should adjust ns so that it cooresponds to * the actual time that the device will use. */static void pci230_ns_to_timer(unsigned int *ns,int round){	unsigned int divisor0, divisor1;	i8253_cascade_ns_to_timer_2div(PCI230_TIMEBASE_10MHZ, &divisor0, &divisor1, ns, TRIG_ROUND_MASK);	return;}/*  *  Set ZCLK_CT0 to square wave mode with period of ns. *  Default clk source for ADC. */static void pci230_z2_ct0(comedi_device *dev, unsigned int *ns,int round){	/* For two cascaded counter/timers, calculate the divide ratios required to give a square wave of period ns. */	i8253_cascade_ns_to_timer_2div(PCI230_TIMEBASE_10MHZ, &devpriv->divisor2, &devpriv->divisor0, ns, TRIG_ROUND_MASK);    /* Generic i8254_load calls; program counters' divide ratios. */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 2, devpriv->divisor2, 3);	/* Counter 2, divisor2, square wave (8254 mode 3). */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 0, devpriv->divisor0, 3);	/* Counter 0, divisor0, square wave (8254 mode 3). */	/* PCI 230 specific - ties up counter clk inputs with clk sources */	outb(PCI230_ZCLK_CT2 | PCI230_ZCLK_SRC_10MHZ, devpriv->pci_iobase + PCI230_ZCLK_SCE);	/* Program counter 2's input clock source. */	outb(PCI230_ZCLK_CT0 | PCI230_ZCLK_SRC_OUTNM1, devpriv->pci_iobase + PCI230_ZCLK_SCE);	/* Program counter 0's input clock source. */	return;}static void pci230_cancel_ct0(comedi_device *dev){	devpriv->divisor2 = 0;	devpriv->divisor0 = 0; 	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 2, devpriv->divisor2, 0);	/* Counter 2, divisor2, 8254 mode 0. */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 0, devpriv->divisor0, 0);	/* Counter 0, divisor0, 8254 mode 0. */}/*  *  Set ZCLK_CT1 to square wave mode with period of ns. *  Default clk source for DAC. */static void pci230_z2_ct1(comedi_device *dev, unsigned int *ns,int round){	/* For two cascaded counter/timers, calculate the divide ratios required to give a square wave of period ns. */	i8253_cascade_ns_to_timer_2div(PCI230_TIMEBASE_10MHZ, &devpriv->divisor0, &devpriv->divisor1, ns, TRIG_ROUND_MASK);    /* Generic i8254_load calls; program counters' divide ratios. */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 0, devpriv->divisor0, 3);	/* Counter 0, divisor0, square wave (8254 mode 3). */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 1, devpriv->divisor1, 3);	/* Counter 1, divisor1, square wave (8254 mode 3). */	/* PCI 230 specific - ties up counter clk inputs with clk sources */	outb(PCI230_ZCLK_CT0 | PCI230_ZCLK_SRC_10MHZ, devpriv->pci_iobase + PCI230_ZCLK_SCE);	/* Program counter 0's input clock source. */	outb(PCI230_ZCLK_CT1 | PCI230_ZCLK_SRC_OUTNM1, devpriv->pci_iobase + PCI230_ZCLK_SCE);	/* Program counter 1's input clock source. */	return;}static void pci230_cancel_ct1(comedi_device *dev){	devpriv->divisor0 = 0;	devpriv->divisor1 = 0; 	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 0, devpriv->divisor0, 0);	/* Counter 0, divisor0, 8254 mode 0. */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 1, devpriv->divisor1, 0);	/* Counter 1, divisor1, 8254 mode 0. */}/*  *  Set ZCLK_CT2 to square wave mode with period of ns. *  Default clk source for external freq. generator (COMEDI_SUBD_TIMER). */static void pci230_z2_ct2(comedi_device *dev, unsigned int *ns,int round){	/* For two cascaded counter/timers, calculate the divide ratios required to give a square wave of period ns. */	i8253_cascade_ns_to_timer_2div(PCI230_TIMEBASE_10MHZ, &devpriv->divisor1, &devpriv->divisor2, ns, TRIG_ROUND_MASK);    /* Generic i8254_load calls; program counters' divide ratios. */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 1, devpriv->divisor1, 3);	/* Counter 1, divisor1, square wave (8254 mode 3). */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 2, devpriv->divisor2, 3);	/* Counter 2, divisor2, square wave (8254 mode 3). */	/* PCI 230 specific - ties up counter clk inputs with clk sources */	outb(PCI230_ZCLK_CT1 | PCI230_ZCLK_SRC_10MHZ, devpriv->pci_iobase + PCI230_ZCLK_SCE);	/* Program counter 1's input clock source. */	outb(PCI230_ZCLK_CT2 | PCI230_ZCLK_SRC_OUTNM1, devpriv->pci_iobase + PCI230_ZCLK_SCE);	/* Program counter 2's input clock source. */	return;}static void pci230_cancel_ct2(comedi_device *dev){	devpriv->divisor1 = 0;	devpriv->divisor2 = 0; 	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 1, devpriv->divisor1, 0);	/* Counter 1, divisor1, 8254 mode 0. */	i8254_load(devpriv->pci_iobase + PCI230_Z2_CT0, 2, devpriv->divisor2, 0);	/* Counter 2, divisor2, 8254 mode 0. */}/* Interrupt handler */static void pci230_interrupt(int irq, void *d, struct pt_regs *regs){	int status_int;	comedi_device *dev = (comedi_device*) d;	comedi_subdevice *s;	/* Read interrupt status/enable register. */	status_int = inb(devpriv->pci_iobase + PCI230_INT_SCE);	/* Disable all of board's interrupts.	 * (Only those interrrupts that need re-enabling, are, later in the handler).  */	devpriv->ier = PCI230_INT_DISABLE; 	outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	/* 	 * Check the source of interrupt and handle it.	 * The PCI230 can cope with concurrent ADC, DAC, PPI C0 and C3 interrupts.	 * However, at present (Comedi-0.7.60) does not allow concurrent	 * execution of commands, instructions or a mixture of the two.	 */	if (status_int == PCI230_INT_DISABLE) {		printk("comedi%d: amplc_pci230::pci230_interrupt spurious interrupt",dev->minor);	}		if (status_int & PCI230_INT_ZCLK_CT1) {		s = dev->write_subdev;		s->async->events = 0;		pci230_handle_ao(dev, s);		comedi_event(dev, s, s->async->events);		s->async->events = 0;	}	if (status_int & PCI230_INT_ADC) {		s = dev->read_subdev;		s->async->events = 0;		pci230_handle_ai(dev, s);		comedi_event(dev, s, s->async->events);		s->async->events = 0;	}	return;}static void pci230_handle_ao(comedi_device *dev, comedi_subdevice *s) {	sampl_t data;	int i, ret;	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	for (i = 0; i < cmd->chanlist_len; i++) {		/* Read sample from Comedi's circular buffer. */		ret = comedi_buf_get(s->async, &data);		if(ret < 0) {			comedi_error(dev, "buffer underrun");			return;										// XXX does comedi_buf_get set s->async->events with appropriate flags in this instance?		}		/* Write value to DAC. */		pci230_ao_write(dev, data, cmd->chanlist[i]);		if(async->cmd.stop_src == TRIG_COUNT) {			if(devpriv->ao_count > 0) devpriv->ao_count--;			if(devpriv->ao_count == 0) break;		}	}	if(devpriv->ao_count == 0 && devpriv->ao_stop == 0) {		/* End of DAC. */		async->events |= COMEDI_CB_EOA;		pci230_ao_cancel(dev, s);	}	else {		/* More samples required, tell Comedi to block. */		async->events |= COMEDI_CB_BLOCK;		/* Enable DAC (conversion complete) interrupt (and leave any other enabled interrupts as they are). */		devpriv->ier |= PCI230_INT_ZCLK_CT1;		outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	}	return;}static void pci230_handle_ai(comedi_device *dev, comedi_subdevice *s) {	int error = 0;	int status_fifo;		/* Read FIFO state. */	status_fifo = inw(dev->iobase + PCI230_ADCCON);		if (status_fifo & PCI230_ADC_FIFO_FULL) {		/* Report error otherwise FIFO overruns will go unnoticed by the caller. */		comedi_error(dev, "FIFO overrun");		error++;	}	else if (status_fifo & PCI230_ADC_FIFO_HALF) {		/* FIFO is at least half full. */		pci230_handle_fifo_half_full(dev, s);	}	else if (status_fifo & PCI230_ADC_FIFO_EMPTY) {		/* FIFO empty but we got an interrupt. */		printk("comedi%d: amplc_pci230::pci230_handle_ai FIFO empty - spurious interrupt\n",dev->minor);	}	else {		/* FIFO is less than half full, but not empty. */		pci230_handle_fifo_not_empty(dev, s);	}	if (error) {		/* Cancel sampled conversion. */		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;		pci230_ai_cancel(dev, s);		}	if(devpriv->ai_count == 0 && devpriv->ai_stop == 0) {		/* Acquisition complete. */		s->async->events |= COMEDI_CB_EOA;		pci230_ai_cancel(dev, s);			/* disable hardware conversions */	}	else {		/* More samples required, tell Comedi to block. */		s->async->events |= COMEDI_CB_BLOCK;		/* Enable ADC (conversion complete) interrupt (and leave any other enabled interrupts as they are). */		devpriv->ier |= PCI230_INT_ADC;		outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	}	return;}static void pci230_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s) {	int i;	for (i = 0; i < 2048; i++) {		/* Read sample and store in Comedi's circular buffer. */		comedi_buf_put(s->async, pci230_ai_read(dev));		if(s->async->cmd.stop_src == TRIG_COUNT)		{			if(--devpriv->ai_count == 0) {				/* Acquisition complete. */				return;			}		}	}	/* More samples required. */	return;}static void pci230_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s) {	while (devpriv->ai_count != 0) {		if (inw(dev->iobase + PCI230_ADCCON) & PCI230_ADC_FIFO_EMPTY) {			/* The FIFO is empty, block. */			return;		}		/* There are sample(s) to read from FIFO, read one and store in Comedi's circular buffer. */		comedi_buf_put(s->async, pci230_ai_read(dev));		if(devpriv->ai_count > 0) devpriv->ai_count--;	}	/* Acquisition complete. */	return;}static int pci230_ao_cancel(comedi_device *dev, comedi_subdevice *s) {	devpriv->ao_count = 0;	devpriv->ao_stop = 0;	/* Stop counter/timers. */	pci230_cancel_ct1(dev);	/* Disable DAC interrupt. */	devpriv->ier &= ~PCI230_INT_ZCLK_CT1;	outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	return 0;}static int pci230_ai_cancel(comedi_device *dev, comedi_subdevice *s) {	devpriv->ai_count = 0;	devpriv->ai_stop = 0;	/* Stop counter/timers. */	pci230_cancel_ct0(dev);	/* Disable ADC interrupt. */	devpriv->ier &= ~PCI230_INT_ADC;	outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE);	/* Reset FIFO and set start conversion source to none. */	outw(PCI230_ADC_FIFO_RESET | PCI230_ADC_TRIG_NONE, dev->iobase + PCI230_ADCCON);	/* Clear channel scan list. */	outw(0x0000, dev->iobase + PCI230_ADCEN);	/* Clear channel gains. */	outw(0x0000, dev->iobase + PCI230_ADCG);	return 0;}

⌨️ 快捷键说明

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