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

📄 cb_pcidas64.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		ai_se_chans:	64,		ai_bits:	14,		ai_speed:	1000,		ao_nchan: 2,		ao_scan_speed:	10000,		layout:	LAYOUT_64XX,		ai_range_table:	&ai_ranges_64xx,		ai_fifo:	ai_fifo_64xx,		has_8255 : 1,	},	{		name:		"pci-das64/m2/14",		device_id:	0,	// XXX		ai_se_chans:	64,		ai_bits:	14,		ai_speed:	500,		ao_nchan: 2,		ao_scan_speed:	10000,		layout:	LAYOUT_64XX,		ai_range_table:	&ai_ranges_64xx,		ai_fifo:	ai_fifo_64xx,		has_8255 : 1,	},	{		name:		"pci-das64/m3/14",		device_id:	0,	// XXX		ai_se_chans:	64,		ai_bits:	14,		ai_speed:	333,		ao_nchan: 2,		ao_scan_speed:	10000,		layout:	LAYOUT_64XX,		ai_range_table:	&ai_ranges_64xx,		ai_fifo:	ai_fifo_64xx,		has_8255 : 1,	},#endif};// Number of boards in cb_pcidas_boardsstatic inline unsigned int num_boards( void ){	return sizeof( pcidas64_boards ) / sizeof( pcidas64_board );}static struct pci_device_id pcidas64_pci_table[] __devinitdata = {	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0 }};MODULE_DEVICE_TABLE(pci, pcidas64_pci_table);/* * Useful for shorthand access to the particular board structure */static inline pcidas64_board* board( const comedi_device *dev ){	return (pcidas64_board *)dev->board_ptr;}struct ext_clock_info{	unsigned int convert_divisor;	// master clock divisor to use for conversions with external master clock	unsigned int scan_divisor;	// master clock divisor to use for scans with external master clock	unsigned int chanspec;	// chanspec for master clock input};/* this structure is for data unique to this hardware driver. */typedef struct{	struct pci_dev *hw_dev;	// pointer to board's pci_dev struct	// base addresses (physical)	unsigned long plx9080_phys_iobase;	unsigned long main_phys_iobase;	unsigned long dio_counter_phys_iobase;	// base addresses (ioremapped)	unsigned long plx9080_iobase;	unsigned long main_iobase;	unsigned long dio_counter_iobase;	// local address (used by dma controller)	uint32_t local0_iobase;	uint32_t local1_iobase;	volatile unsigned int ai_count;	// number of analog input samples remaining	uint16_t *ai_buffer[DMA_RING_COUNT];	// dma buffers for analog input	dma_addr_t ai_buffer_phys_addr[DMA_RING_COUNT];	// physical addresses of ai dma buffers	struct plx_dma_desc *dma_desc;	// array of dma descriptors read by plx9080, allocated to get proper alignment	dma_addr_t dma_desc_phys_addr;	// physical address of dma descriptor array	volatile unsigned int dma_index;	// index of the dma descriptor/buffer that is currently being used	volatile unsigned int ao_count;	// number of analog output samples remaining	volatile unsigned int ao_value[2];	// remember what the analog outputs are set to, to allow readback	unsigned int hw_revision;	// stc chip hardware revision number	volatile unsigned int intr_enable_bits;	// last bits sent to INTR_ENABLE_REG register	volatile uint16_t adc_control1_bits;	// last bits sent to ADC_CONTROL1_REG register	volatile uint16_t fifo_size_bits;	// last bits sent to FIFO_SIZE_REG register	volatile uint16_t hw_config_bits;	// last bits sent to HW_CONFIG_REG register	volatile uint32_t plx_control_bits;	// last bits written to plx9080 control register	volatile uint32_t plx_intcsr_bits;	// last bits written to plx interrupt control and status register	volatile int calibration_source;	// index of calibration source readable through ai ch0	volatile uint8_t i2c_cal_range_bits;	// bits written to i2c calibration/range register	volatile unsigned int ext_trig_falling;	// configure digital triggers to trigger on falling edge	// states of various devices stored to enable read-back	unsigned int ad8402_state[2];	unsigned int caldac_state[8];	volatile unsigned ai_cmd_running : 1;	unsigned int ai_fifo_segment_length;	struct ext_clock_info ext_clock;} pcidas64_private;/* inline function that makes it easier to * access the private structure. */static inline pcidas64_private* priv(comedi_device *dev){	return dev->private;}/* * The comedi_driver structure tells the Comedi core module * which functions to call to configure/deconfigure (attach/detach) * the board, and also about the kernel module that contains * the device code. */static int attach(comedi_device *dev,comedi_devconfig *it);static int detach(comedi_device *dev);static comedi_driver driver_cb_pcidas={	driver_name:	"cb_pcidas64",	module:		THIS_MODULE,	attach:		attach,	detach:		detach,};static int ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int ai_config_insn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int ao_readback_insn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int ai_cmd(comedi_device *dev,comedi_subdevice *s);static int ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);//static int ao_cmd(comedi_device *dev,comedi_subdevice *s);//static int ao_inttrig(comedi_device *dev, comedi_subdevice *subdev, unsigned int trig_num);//static int ao_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static void handle_interrupt(int irq, void *d, struct pt_regs *regs);static int ai_cancel(comedi_device *dev, comedi_subdevice *s);//static int ao_cancel(comedi_device *dev, comedi_subdevice *s);static int dio_callback(int dir, int port, int data, unsigned long arg);static int dio_callback_4020(int dir, int port, int data, unsigned long arg);static int di_rbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int do_wbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int dio_60xx_config_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int dio_60xx_wbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int calib_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int calib_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int ad8402_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static void ad8402_write( comedi_device *dev, unsigned int channel, unsigned int value );static int ad8402_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int eeprom_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static void check_adc_timing(comedi_cmd *cmd);static unsigned int get_divisor(unsigned int ns, unsigned int flags);static void i2c_write(comedi_device *dev, unsigned int address, const uint8_t *data, unsigned int length);static void caldac_write( comedi_device *dev, unsigned int channel, unsigned int value );static int caldac_8800_write(comedi_device *dev, unsigned int address, uint8_t value);//static int dac_1590_write(comedi_device *dev, unsigned int dac_a, unsigned int dac_b);static int caldac_i2c_write(comedi_device *dev, unsigned int caldac_channel, unsigned int value);static void abort_dma(comedi_device *dev, unsigned int channel);static void disable_plx_interrupts( comedi_device *dev );static int set_ai_fifo_size( comedi_device *dev, unsigned int num_samples );static unsigned int ai_fifo_size( comedi_device *dev );static int set_ai_fifo_segment_length( comedi_device *dev, unsigned int num_entries );static void disable_ai_pacing( comedi_device *dev );static void disable_ai_interrupts( comedi_device *dev );static void enable_ai_interrupts( comedi_device *dev, const comedi_cmd *cmd );COMEDI_INITCLEANUP(driver_cb_pcidas);static unsigned int ai_range_bits_6xxx( const comedi_device *dev, unsigned int range_index ){	comedi_krange *range = &board( dev )->ai_range_table->range[ range_index ];	unsigned int bits = 0;	switch( range->max )	{		case 10000000:			bits = 0x000;			break;		case 5000000:			bits = 0x100;			break;		case 2000000:		case 2500000:			bits = 0x200;			break;		case 1000000:		case 1250000:			bits = 0x300;			break;		case 500000:			bits = 0x400;			break;		case 200000:		case 250000:			bits = 0x500;			break;		case 100000:			bits = 0x600;			break;		case 50000:			bits = 0x700;			break;		default:			comedi_error( dev, "bug! in ai_range_bits_6xxx" );			break;	}	if( range->min == 0 ) bits += 0x900;	return bits;}static inline uint16_t dac_range_bits( const comedi_device *dev,	unsigned int channel, unsigned int range ){	unsigned int code = board(dev)->ao_range_code[ range ];	return ( ( code ) & 0x3 ) << ( 2 * ( ( channel ) & 0x1 ) );};static inline unsigned int hw_revision( const comedi_device *dev, uint16_t hw_status_bits ){	if( board(dev)->layout == LAYOUT_4020)		return ( hw_status_bits >> 13 ) & 0x7;	return ( hw_status_bits >> 12) & 0xf;}// initialize plx9080 chipstatic void init_plx9080(comedi_device *dev){	uint32_t bits;	unsigned long plx_iobase = priv(dev)->plx9080_iobase;	priv(dev)->plx_control_bits = readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG);	// plx9080 dump	DEBUG_PRINT(" plx interrupt status 0x%x\n", readl(plx_iobase + PLX_INTRCS_REG));	DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG));	DEBUG_PRINT(" plx control reg 0x%x\n", priv(dev)->plx_control_bits);	DEBUG_PRINT(" plx revision 0x%x\n", readl(plx_iobase + PLX_REVISION_REG));	DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n", readl(plx_iobase + PLX_DMA0_MODE_REG));	DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n", readl(plx_iobase + PLX_DMA1_MODE_REG));	DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n", readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG));	DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n", readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG));	DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n", readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG));	DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n", readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG));	DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n", readb(plx_iobase + PLX_DMA0_CS_REG));	DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n", readl(plx_iobase + PLX_DMA0_THRESHOLD_REG));	disable_plx_interrupts( dev );	abort_dma(dev, 0);	abort_dma(dev, 1);	// configure dma0 mode	bits = 0;	// enable ready input, not sure if this is necessary	bits |= PLX_DMA_EN_READYIN_BIT;	// enable dma chaining	bits |= PLX_EN_CHAIN_BIT;	// enable interrupt on dma done (probably don't need this, since chain never finishes)	bits |= PLX_EN_DMA_DONE_INTR_BIT;	// don't increment local address during transfers (we are transferring from a fixed fifo register)	bits |= PLX_LOCAL_ADDR_CONST_BIT;	// route dma interrupt to pci bus	bits |= PLX_DMA_INTR_PCI_BIT;	// enable demand mode	bits |= PLX_DEMAND_MODE_BIT;	// enable local burst mode	bits |= PLX_DMA_LOCAL_BURST_EN_BIT;	// 4020 uses 32 bit dma	if(board(dev)->layout == LAYOUT_4020)	{		bits |= PLX_LOCAL_BUS_32_WIDE_BITS;	}else	{	// localspace0 bus is 16 bits wide		bits |= PLX_LOCAL_BUS_16_WIDE_BITS;	}	writel(bits, plx_iobase + PLX_DMA1_MODE_REG);}/* Allocate and initialize the subdevice structures. */static int setup_subdevices(comedi_device *dev){	comedi_subdevice *s;	unsigned long dio_8255_iobase;	int i;	if( alloc_subdevices( dev, 10 ) < 0 )		return -ENOMEM;	s = dev->subdevices + 0;	/* analog input subdevice */	dev->read_subdev = s;	s->type = COMEDI_SUBD_AI;	s->subdev_flags = SDF_READABLE | SDF_GROUND;	if(board(dev)->layout == LAYOUT_60XX)		s->subdev_flags |= SDF_COMMON | SDF_DIFF;	else if(board(dev)->layout == LAYOUT_64XX)		s->subdev_flags |= SDF_DIFF;	/* XXX Number of inputs in differential mode is ignored */	s->n_chan = board(dev)->ai_se_chans;	s->len_chanlist = 0x2000;	s->maxdata = (1 << board(dev)->ai_bits) - 1;	s->range_table = board(dev)->ai_range_table;	s->insn_read = ai_rinsn;	s->insn_config = ai_config_insn;	s->do_cmd = ai_cmd;	s->do_cmdtest = ai_cmdtest;	s->cancel = ai_cancel;	if(board(dev)->layout == LAYOUT_4020)	{		unsigned int i;		uint8_t data;		// set adc to read from inputs (not internal calibration sources)		priv(dev)->i2c_cal_range_bits = adc_src_4020_bits( 4 );		// set channels to +-5 volt input ranges		for( i = 0; i < s->n_chan; i++)			priv(dev)->i2c_cal_range_bits |= attenuate_bit( i );		data = priv(dev)->i2c_cal_range_bits;		i2c_write(dev, RANGE_CAL_I2C_ADDR, &data, sizeof(data));	}	/* analog output subdevice */	s = dev->subdevices + 1;	if(board(dev)->ao_nchan)	{	//	dev->write_subdev = s;		s->type = COMEDI_SUBD_AO;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;		s->n_chan = board(dev)->ao_nchan;		// analog out resolution is the same as analog input resolution, so use ai_bits		s->maxdata = (1 << board(dev)->ai_bits) - 1;		s->range_table = board(dev)->ao_range_table;		s->insn_read = ao_readback_insn;		s->insn_write = ao_winsn;//XXX 4020 can't do paced analog output	//	s->do_cmdtest = ao_cmdtest;	//	s->do_cmd = ao_cmd;	//	s->len_chanlist = board(dev)->ao_nchan;	//	s->cancel = ao_cancel;	} else	{		s->type = COMEDI_SUBD_UNUSED;	}	// digital input	s = dev->subdevices + 2;	if(board(dev)->layout == LAYOUT_64XX)	{		s->type = COMEDI_SUBD_DI;		s->subdev_flags = SDF_READABLE;		s->n_chan = 4;		s->maxdata = 1;		s->range_table = &range_digital;		s->insn_bits = di_rbits;	} else		s->type = COMEDI_SUBD_UNUSED;	// digital output	if(board(dev)->layout == LAYOUT_64XX)	{		s = dev->subdevices + 3;		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 = do_wbits;	} else		s->type = COMEDI_SUBD_UNUSED;	/* 8255 */	s = dev->subdevices + 4;	if( board(dev)->has_8255 )	{		if(board(dev)->layout == LAYOUT_4020)		{			dio_8255_iobase = priv(dev)->main_iobase + I8255_4020_REG;			subdev_8255_init(dev, s, dio_callback_4020, dio_8255_iobase);		} else		{			dio_8255_iobase = priv(dev)->dio_counter_iobase + DIO_8255_OFFSET;			subdev_8255_init(dev, s, dio_callback, dio_8255_iobase);		}	}else		s->type = COMEDI_SUBD_UNUSED;	// 8 channel dio for 60xx	s = dev->subdevices + 5;	if(board(dev)->layout == LAYOUT_60XX)	{		s->type = COMEDI_SUBD_DIO;		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;		s->n_chan = 8;		s->maxdata = 1;		s->range_table = &range_digital;		s->insn_config = dio_60xx_config_insn;		s->insn_bits = dio_60xx_wbits;	} else		s->type = COMEDI_SUBD_UNUSED;	// caldac	s = dev->subdevices + 6;	s->type=COMEDI_SUBD_CALIB;	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;	s->n_chan = 8;	if(board(dev)->layout == LAYOUT_4020)		s->maxdata = 0xfff;	else		s->maxdata = 0xff;	s->insn_read = calib_read_insn;	s->insn_write = calib_write_insn;	for( i = 0; i < s->n_chan; i++ )		caldac_write( dev, i, s->maxdata / 2 );	// 2 channel ad8402 potentiometer	s = dev->subdevices + 7;	if(board(dev)->layout == LAYOUT_64XX)	{		s->type = COMEDI_SUBD_CALIB;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;		s->n_chan = 2;		s->insn_read = ad8402_read_insn;		s->insn_write = ad8402_write_insn;		s->maxdata = 0xff;		for( i = 0; i < s->n_chan; i++ )			ad8402_write( dev, i, s->maxdata / 2 );	} else		s->type = COMEDI_SUBD_UNUSED;	//serial EEPROM, if present	s = dev->subdevices + 8;	if(priv(dev)->plx_control_bits & CTL_EECHK)	{		s->type = COMEDI_SUBD_MEMORY;		s->subdev_flags = SDF_READABLE | SDF_INTERNAL;		s->n_chan = 128;		s->maxdata = 0xffff;		s->insn_read = eeprom_read_insn;	} else		s->type = COMEDI_SUBD_UNUSED;	// user counter subd XXX	s = dev->subdevices + 9;	s->type = COMEDI_SUBD_UNUSED;	return 0;}

⌨️ 快捷键说明

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