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

📄 cb_pcidas.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	comedi_cmd *cmd = &async->cmd;	unsigned int i;	unsigned long flags;	// set channel limits, gain	comedi_spin_lock_irqsave( &dev->spinlock, flags );	for(i = 0; i < cmd->chanlist_len; i++)	{		// enable channel		devpriv->ao_control_bits |= DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));		// set range		devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),			CR_RANGE(cmd->chanlist[i]));	}	// disable analog out before settings pacer source and count values	outw( devpriv->ao_control_bits, devpriv->control_status + DAC_CSR );	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// clear fifo	outw(0, devpriv->ao_registers + DACFIFOCLR);	// load counters	if(cmd->scan_begin_src == TRIG_TIMER)	{		i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->ao_divisor1),			&(devpriv->ao_divisor2), &(cmd->scan_begin_arg),			cmd->flags);		/* Write the values of ctr1 and ctr2 into counters 1 and 2 */		i8254_load(devpriv->pacer_counter_dio + DAC8254, 1, devpriv->ao_divisor1, 2);		i8254_load(devpriv->pacer_counter_dio + DAC8254, 2, devpriv->ao_divisor2, 2);	}	// set number of conversions	if(cmd->stop_src == TRIG_COUNT)	{		devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;	}	// set pacer source	comedi_spin_lock_irqsave( &dev->spinlock, flags );	switch(cmd->scan_begin_src)	{		case TRIG_TIMER:			devpriv->ao_control_bits |= DAC_PACER_INT;			break;		case TRIG_EXT:			devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;			break;		default:			comedi_spin_unlock_irqrestore( &dev->spinlock, flags );			comedi_error(dev, "error setting dac pacer source");			return -1;			break;	}	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	async->inttrig = cb_pcidas_ao_inttrig;	return 0;}static int cb_pcidas_ao_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trig_num){	unsigned int num_bytes, num_points = thisboard->fifo_size;	comedi_async *async = s->async;	comedi_cmd *cmd = &s->async->cmd;	unsigned long flags;	if(trig_num != 0)		return -EINVAL;	// load up fifo	if( cmd->stop_src == TRIG_COUNT &&		devpriv->ao_count < num_points	)		num_points = devpriv->ao_count;	num_bytes = cfc_read_array_from_buffer( s, devpriv->ao_buffer,		num_points * sizeof( sampl_t ) );	num_points = num_bytes / sizeof( sampl_t );	if(cmd->stop_src == TRIG_COUNT)	{		devpriv->ao_count -= num_points;	}	// write data to board's fifo	outsw( devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes );	// enable dac half-full and empty interrupts	comedi_spin_lock_irqsave( &dev->spinlock, flags );	devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;#ifdef CB_PCIDAS_DEBUG	rt_printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits);#endif	// enable and clear interrupts	outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, devpriv->control_status + INT_ADCFIFO);	// start dac	devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);#ifdef CB_PCIDAS_DEBUG	rt_printk("comedi: sent 0x%x to dac control\n", devpriv->ao_control_bits);#endif	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	async->inttrig = NULL;	return 0;}static void cb_pcidas_interrupt(int irq, void *d, struct pt_regs *regs){	comedi_device *dev = (comedi_device*) d;	comedi_subdevice *s = dev->read_subdev;	comedi_async *async;	int status, s5933_status;	int half_fifo = thisboard->fifo_size / 2;	unsigned int num_samples, i;	static const int timeout = 10000;	unsigned long flags;		if(dev->attached == 0)	{		comedi_error(dev, "premature interrupt");	}	async = s->async;	async->events = 0;	s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);#ifdef CB_PCIDAS_DEBUG	rt_printk("intcsr 0x%x\n", s5933_status);	rt_printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF));#endif	if( ( INTCSR_INTR_ASSERTED & s5933_status ) == 0 )		return;	// make sure mailbox 4 is empty	inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);	// clear interrupt on amcc s5933	outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR);	status = inw(devpriv->control_status + INT_ADCFIFO);#ifdef CB_PCIDAS_DEBUG	if((status & (INT | EOAI | LADFUL | DAHFI | DAEMI)) == 0)	{		comedi_error(dev, "spurious interrupt");	}#endif	// check for analog output interrupt	if(status & (DAHFI | DAEMI))	{		handle_ao_interrupt(dev, status);	}	// check for analog input interrupts	// if fifo half-full	if(status & ADHFI)	{		// read data		num_samples = half_fifo;		if(async->cmd.stop_src == TRIG_COUNT &&			num_samples > devpriv->count)		{			num_samples = devpriv->count;		}		insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer, num_samples);		cfc_write_array_to_buffer( s, devpriv->ai_buffer, num_samples * sizeof( sampl_t ) );		devpriv->count -= num_samples;		if(async->cmd.stop_src == TRIG_COUNT &&			devpriv->count == 0)		{			async->events |= COMEDI_CB_EOA;			cb_pcidas_cancel(dev, s);		}		// clear half-full interrupt latch		comedi_spin_lock_irqsave( &dev->spinlock, flags );		outw(devpriv->adc_fifo_bits | INT, devpriv->control_status + INT_ADCFIFO);		comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// else if fifo not empty	}else if(status & (ADNEI | EOBI))	{		for(i = 0; i < timeout; i++)		{			// break if fifo is empty			if((ADNE & inw(devpriv->control_status + INT_ADCFIFO)) == 0)				break;			cfc_write_to_buffer( s, inw( devpriv->adc_fifo ) );			if(async->cmd.stop_src == TRIG_COUNT &&				--devpriv->count == 0)			{		/* end of acquisition */				cb_pcidas_cancel(dev, s);				async->events |= COMEDI_CB_EOA;				break;			}		}		// clear not-empty interrupt latch		comedi_spin_lock_irqsave( &dev->spinlock, flags );		outw(devpriv->adc_fifo_bits | INT, devpriv->control_status + INT_ADCFIFO);		comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	}else if(status & EOAI)	{		comedi_error(dev, "bug! encountered end of aquisition interrupt?");		// clear EOA interrupt latch		comedi_spin_lock_irqsave( &dev->spinlock, flags );		outw(devpriv->adc_fifo_bits | EOAI, devpriv->control_status + INT_ADCFIFO);		comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	}	//check for fifo overflow	if(status & LADFUL)	{		comedi_error(dev, "fifo overflow");		// clear overflow interrupt latch		comedi_spin_lock_irqsave( &dev->spinlock, flags );		outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO);		comedi_spin_unlock_irqrestore( &dev->spinlock, flags );		cb_pcidas_cancel(dev, s);		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;	}	comedi_event(dev, s, async->events);	return;}static void handle_ao_interrupt(comedi_device *dev, unsigned int status){	comedi_subdevice *s = dev->write_subdev;	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	unsigned int half_fifo = thisboard->fifo_size / 2;	unsigned int num_points;	unsigned int flags;	async->events = 0;	if(status & DAEMI)	{		// clear dac empty interrupt latch		comedi_spin_lock_irqsave( &dev->spinlock, flags );		outw(devpriv->adc_fifo_bits | DAEMI, devpriv->control_status + INT_ADCFIFO);		comedi_spin_unlock_irqrestore( &dev->spinlock, flags );		if(inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY)		{			if(cmd->stop_src == TRIG_NONE ||				(cmd->stop_src == TRIG_COUNT && devpriv->ao_count))			{				comedi_error(dev, "dac fifo underflow");				cb_pcidas_ao_cancel(dev, s);				async->events |= COMEDI_CB_ERROR;			}			async->events |= COMEDI_CB_EOA;		}	}else if(status & DAHFI)	{		unsigned int num_bytes;		// figure out how many points we are writing to fifo		num_points = half_fifo;		if(cmd->stop_src == TRIG_COUNT &&			devpriv->ao_count < num_points)			num_points = devpriv->ao_count;		num_bytes = cfc_read_array_from_buffer( s, devpriv->ao_buffer, num_points * sizeof( sampl_t ) );		num_points = num_bytes / sizeof( sampl_t );		if(async->cmd.stop_src == TRIG_COUNT)		{			devpriv->ao_count -= num_points;		}		// write data to board's fifo		outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_points);		// clear half-full interrupt latch		comedi_spin_lock_irqsave( &dev->spinlock, flags );		outw(devpriv->adc_fifo_bits | DAHFI, devpriv->control_status + INT_ADCFIFO);		comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	}	comedi_event(dev, s, async->events);}// cancel analog input commandstatic int cb_pcidas_cancel(comedi_device *dev, comedi_subdevice *s){	unsigned long flags;	comedi_spin_lock_irqsave( &dev->spinlock, flags );	// disable interrupts	devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;	outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// disable start trigger source and burst mode	outw(0, devpriv->control_status + TRIG_CONTSTAT);	// software pacer source	outw(0, devpriv->control_status + ADCMUX_CONT);	return 0;}// cancel analog output commandstatic int cb_pcidas_ao_cancel(comedi_device *dev, comedi_subdevice *s){	unsigned long flags;	comedi_spin_lock_irqsave( &dev->spinlock, flags );	// disable interrupts	devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;	outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);	// disable output	devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;	outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	return 0;}static void cb_pcidas_load_counters(comedi_device *dev, unsigned int *ns, int rounding_flags){	i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),		&(devpriv->divisor2), ns, rounding_flags & TRIG_ROUND_MASK);	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */	i8254_load(devpriv->pacer_counter_dio + ADC8254, 1, devpriv->divisor1, 2);	i8254_load(devpriv->pacer_counter_dio + ADC8254, 2, devpriv->divisor2, 2);}static void write_calibration_bitstream( comedi_device *dev, unsigned int register_bits,	unsigned int bitstream, unsigned int bitstream_length ){	static const int write_delay = 1;	unsigned int bit;	for( bit = 1 << (bitstream_length - 1); bit; bit >>= 1)	{		if(bitstream & bit)			register_bits |= SERIAL_DATA_IN_BIT;		else			register_bits &= ~SERIAL_DATA_IN_BIT;		comedi_udelay( write_delay );		outw( register_bits, devpriv->control_status + CALIBRATION_REG);	}}static int caldac_8800_write(comedi_device *dev, unsigned int address, uint8_t value){	static const int num_caldac_channels = 8;	static const int bitstream_length = 11;	unsigned int bitstream = ((address & 0x7) << 8) | value;	static const int caldac_8800_comedi_udelay = 1;	if(address >= num_caldac_channels)	{		comedi_error(dev, "illegal caldac channel");		return -1;	}	if( value == devpriv->caldac_value[ address ] ) return 1;	devpriv->caldac_value[ address ] = value;	write_calibration_bitstream( dev, 0, bitstream, bitstream_length );	comedi_udelay(caldac_8800_comedi_udelay);	outw(SELECT_8800_BIT, devpriv->control_status + CALIBRATION_REG);	comedi_udelay(caldac_8800_comedi_udelay);	outw(0, devpriv->control_status + CALIBRATION_REG);	return 1;}static int trimpot_7376_write(comedi_device *dev, uint8_t value){	static const int bitstream_length = 7;	unsigned int bitstream = value & 0x7f;	unsigned int register_bits;	static const int ad7376_comedi_udelay = 1;	register_bits = SELECT_TRIMPOT_BIT;	comedi_udelay( ad7376_comedi_udelay );	outw( register_bits, devpriv->control_status + CALIBRATION_REG);	write_calibration_bitstream( dev, register_bits, bitstream, bitstream_length );	comedi_udelay(ad7376_comedi_udelay);	outw(0, devpriv->control_status + CALIBRATION_REG);	return 0;}/* For 1602/16 only * ch 0 : adc gain * ch 1 : adc postgain offset */static int trimpot_8402_write(comedi_device *dev, unsigned int channel, uint8_t value){	// XXX check docs, this function is just a guess	static const int bitstream_length = 10;	unsigned int bitstream = ( ( channel & 0x1 ) << 8 ) | ( value & 0xff );	unsigned int register_bits;	static const int ad8402_comedi_udelay = 1;	register_bits = SELECT_TRIMPOT_BIT;	comedi_udelay( ad8402_comedi_udelay );	outw( register_bits, devpriv->control_status + CALIBRATION_REG);	write_calibration_bitstream( dev, register_bits, bitstream, bitstream_length );	comedi_udelay(ad8402_comedi_udelay);	outw(0, devpriv->control_status + CALIBRATION_REG);	return 0;}static int wait_for_nvram_ready( unsigned long s5933_base_addr ){	static const int timeout = 1000;	unsigned int i;	for( i = 0; i < timeout; i++)	{		if( ( inb( s5933_base_addr + AMCC_OP_REG_MCSR_NVCMD ) & MCSR_NV_BUSY ) == 0 )			return 0;		comedi_udelay( 1 );	}	return -1;}static int nvram_read( comedi_device *dev, unsigned int address, uint8_t *data ){	unsigned long iobase = devpriv->s5933_config;	if( wait_for_nvram_ready( iobase ) < 0 )		return -ETIMEDOUT;	outb( MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, iobase + AMCC_OP_REG_MCSR_NVCMD );	outb( address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA );	outb( MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, iobase + AMCC_OP_REG_MCSR_NVCMD );	outb( ( address >> 8 ) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA );	outb( MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD );	if( wait_for_nvram_ready( iobase ) < 0 )		return -ETIMEDOUT;	*data = inb( iobase + AMCC_OP_REG_MCSR_NVDATA );	return 0;}/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_cb_pcidas);

⌨️ 快捷键说明

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