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

📄 cb_pcidda.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}/* * I will program this later... ;-) *static int cb_pcidda_ai_cmd(comedi_device *dev,comedi_subdevice *s){	printk("cb_pcidda_ai_cmd\n");	printk("subdev: %d\n", cmd->subdev);	printk("flags: %d\n", cmd->flags);	printk("start_src: %d\n", cmd->start_src);	printk("start_arg: %d\n", cmd->start_arg);	printk("scan_begin_src: %d\n", cmd->scan_begin_src);	printk("convert_src: %d\n", cmd->convert_src);	printk("convert_arg: %d\n", cmd->convert_arg);	printk("scan_end_src: %d\n", cmd->scan_end_src);	printk("scan_end_arg: %d\n", cmd->scan_end_arg);	printk("stop_src: %d\n", cmd->stop_src);	printk("stop_arg: %d\n", cmd->stop_arg);	printk("chanlist_len: %d\n", cmd->chanlist_len);}*/static int cb_pcidda_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,	comedi_cmd *cmd){	int err=0;	int tmp;	/* cmdtest tests a particular command to see if it is valid.	 * Using the cmdtest ioctl, a user can create a valid cmd	 * and then have it executes by the cmd ioctl.	 *	 * cmdtest returns 1,2,3,4 or 0, depending on which tests	 * the command passes. */	/* step 1: make sure trigger sources are trivially valid */	tmp = cmd->start_src;	cmd->start_src &= TRIG_NOW;	if(!cmd->start_src || tmp != cmd->start_src)		err++;	tmp = cmd->scan_begin_src;	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;	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 */	/* note that mutual compatiblity is not an issue here */	if(cmd->scan_begin_src != TRIG_TIMER && cmd->scan_begin_src != TRIG_EXT)		err++;	if(cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)		err++;	if(cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT)		err++;	if(err) return 2;	/* step 3: make sure arguments are trivially compatible */	if(cmd->start_arg!=0)	{		cmd->start_arg=0;		err++;	}#define MAX_SPEED	10000		/* in nanoseconds */#define MIN_SPEED	1000000000	/* in nanoseconds */	if (cmd->scan_begin_src == TRIG_TIMER)	{		if (cmd->scan_begin_arg < MAX_SPEED)		{			cmd->scan_begin_arg = MAX_SPEED;			err++;		}		if (cmd->scan_begin_arg > MIN_SPEED)		{			cmd->scan_begin_arg = MIN_SPEED;			err++;		}	}	else	{		/* external trigger */		/* should be level/edge, hi/lo specification here */		/* should specify multiple external triggers */		if (cmd->scan_begin_arg > 9)		{			cmd->scan_begin_arg = 9;			err++;		}	}	if (cmd->convert_src == TRIG_TIMER)	{		if (cmd->convert_arg < MAX_SPEED)		{			cmd->convert_arg = MAX_SPEED;			err++;		}		if (cmd->convert_arg>MIN_SPEED)		{			cmd->convert_arg = MIN_SPEED;			err++;		}	}	else	{		/* external trigger */		/* see above */		if (cmd->convert_arg > 9)		{			cmd->convert_arg = 9;			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 > 0x00ffffff)		{			cmd->stop_arg = 0x00ffffff;			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->scan_begin_src == TRIG_TIMER)	{		tmp = cmd->scan_begin_arg;		cb_pcidda_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);		if(tmp != cmd->scan_begin_arg)			err++;	}	if(cmd->convert_src == TRIG_TIMER)	{		tmp=cmd->convert_arg;		cb_pcidda_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);		if(tmp != cmd->convert_arg)			err++;		if(cmd->scan_begin_src == TRIG_TIMER &&		  cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg)		{			cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;			err++;		}	}	if(err) return 4;	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 int cb_pcidda_ns_to_timer(unsigned int *ns,int round){	/* trivial timer */	return *ns;}static int cb_pcidda_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){	unsigned int command;	unsigned int channel, range;	channel = CR_CHAN(insn->chanspec);	range = CR_RANGE(insn->chanspec);	// adjust calibration dacs if range has changed	if(range != devpriv->ao_range[channel])		cb_pcidda_calibrate(dev, channel, range);	/* output channel configuration */	command = NOSU | ENABLEDAC;	/* output channel range */	switch (range)	{		case 0:			command |= BIP | RANGE10V;			break;		case 1:			command |= BIP | RANGE5V;			break;		case 2:			command |= BIP | RANGE2V5;			break;		case 3:			command |= UNIP | RANGE10V;			break;		case 4:			command |= UNIP | RANGE5V;			break;		case 5:			command |= UNIP | RANGE2V5;			break;	};	/* output channel specification */	command |= channel << 2;	outw(command, devpriv->dac + DACONTROL);	/* write data */	outw(data[0], devpriv->dac + DADATA + channel * 2);	/* return the number of samples read/written */	return 1;}// lowlevel read from eepromstatic unsigned int cb_pcidda_serial_in(comedi_device *dev){	unsigned int value = 0;	int i;	const int value_width = 16;	// number of bits wide values are	for(i = 1; i <= value_width; i++)	{		// read bits most significant bit first		if(inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT)		{			value |= 1 << (value_width - i);		}	}	return value;}// lowlevel write to eeprom/dacstatic void cb_pcidda_serial_out(comedi_device *dev, unsigned int value, unsigned int num_bits){	int i;	for(i = 1; i <= num_bits; i++)	{		// send bits most significant bit first		if(value & (1 << (num_bits - i)))			devpriv->dac_cal1_bits |= SERIAL_IN_BIT;		else			devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;		outw_p(devpriv->dac_cal1_bits, devpriv->dac + DACALIBRATION1);	}}// reads a 16 bit value from board's eepromstatic unsigned int cb_pcidda_read_eeprom(comedi_device *dev, unsigned int address){	unsigned int i;	unsigned int cal2_bits;	unsigned int value;	const int max_num_caldacs = 4;	// one caldac for every two dac channels	const int read_instruction = 0x6;	// bits to send to tell eeprom we want to read	const int instruction_length = 3;	const int address_length = 8;	// send serial output stream to eeprom	cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT;	// deactivate caldacs (one caldac for every two channels)	for(i = 0; i < max_num_caldacs; i++)	{		cal2_bits |= DESELECT_CALDAC_BIT(i);	}	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);	// tell eeprom we want to read	cb_pcidda_serial_out(dev, read_instruction, instruction_length);	// send address we want to read from	cb_pcidda_serial_out(dev, address, address_length);	value = cb_pcidda_serial_in(dev);	// deactivate eeprom	cal2_bits &= ~SELECT_EEPROM_BIT;	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);	return value;}// writes to 8 bit calibration dacsstatic void cb_pcidda_write_caldac(comedi_device *dev, unsigned int caldac,	unsigned int channel, unsigned int value){	unsigned int cal2_bits;	unsigned int i;	const int num_channel_bits = 3;	// caldacs use 3 bit channel specification	const int num_caldac_bits = 8;	// 8 bit calibration dacs	const int max_num_caldacs = 4;	// one caldac for every two dac channels	/* write 3 bit channel */	cb_pcidda_serial_out(dev, channel, num_channel_bits);	// write 8 bit caldac value	cb_pcidda_serial_out(dev, value, num_caldac_bits);	// latch stream into appropriate caldac	// deselect reference dac	cal2_bits = DESELECT_REF_DAC_BIT;	// deactivate caldacs (one caldac for every two channels)	for(i = 0; i < max_num_caldacs; i++)	{		cal2_bits |= DESELECT_CALDAC_BIT(i);	}	// activate the caldac we want	cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);	// deactivate caldac	cal2_bits |= DESELECT_CALDAC_BIT(caldac);	outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);}// returns caldac that calibrates given analog out channelstatic unsigned int caldac_number(unsigned int channel){	return channel / 2;}// returns caldac channel that provides fine gain for given ao channelstatic unsigned int fine_gain_channel(unsigned int ao_channel){	return 4 * (ao_channel % 2);}// returns caldac channel that provides coarse gain for given ao channelstatic unsigned int coarse_gain_channel(unsigned int ao_channel){	return 1 + 4 * (ao_channel % 2);}// returns caldac channel that provides coarse offset for given ao channelstatic unsigned int coarse_offset_channel(unsigned int ao_channel){	return 2 + 4 * (ao_channel % 2);}// returns caldac channel that provides fine offset for given ao channelstatic unsigned int fine_offset_channel(unsigned int ao_channel){	return 3 + 4 * (ao_channel % 2);}// returns eeprom address that provides offset for given ao channel and rangestatic unsigned int offset_eeprom_address(unsigned int ao_channel, unsigned int range){	return 0x7 + 2 * range + 12 * ao_channel;}// returns eeprom address that provides gain calibration for given ao channel and rangestatic unsigned int gain_eeprom_address(unsigned int ao_channel, unsigned int range){	return 0x8 + 2 * range + 12 * ao_channel;}// returns upper byte of eeprom entry, which gives the coarse adjustment valuesstatic unsigned int eeprom_coarse_byte(unsigned int word){	return (word >> 8) & 0xff;}// returns lower byte of eeprom entry, which gives the fine adjustment valuesstatic unsigned int eeprom_fine_byte(unsigned int word){	return word & 0xff;}// set caldacs to eeprom values for given channel and rangestatic void cb_pcidda_calibrate(comedi_device *dev, unsigned int channel, unsigned int range){	unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;	// remember range so we can tell when we need to readjust calibration	devpriv->ao_range[channel] = range;	// get values from eeprom data	coarse_offset = eeprom_coarse_byte(devpriv->eeprom_data[offset_eeprom_address(channel, range)]);	fine_offset = eeprom_fine_byte(devpriv->eeprom_data[offset_eeprom_address(channel, range)]);	coarse_gain = eeprom_coarse_byte(devpriv->eeprom_data[gain_eeprom_address(channel, range)]);	fine_gain = eeprom_fine_byte(devpriv->eeprom_data[gain_eeprom_address(channel, range)]);	// set caldacs	cb_pcidda_write_caldac(dev, caldac_number(channel), coarse_offset_channel(channel), coarse_offset);	cb_pcidda_write_caldac(dev, caldac_number(channel), fine_offset_channel(channel), fine_offset);	cb_pcidda_write_caldac(dev, caldac_number(channel), coarse_gain_channel(channel), coarse_gain);	cb_pcidda_write_caldac(dev, caldac_number(channel), fine_gain_channel(channel), fine_gain);}/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_cb_pcidda);

⌨️ 快捷键说明

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