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

📄 cb_pcidas.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int cb_pcidas_ai_cmd(comedi_device *dev,comedi_subdevice *s);static int cb_pcidas_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,	comedi_cmd *cmd);static int cb_pcidas_ao_cmd(comedi_device *dev,comedi_subdevice *s);static int cb_pcidas_ao_inttrig(comedi_device *dev, comedi_subdevice *subdev, unsigned int trig_num);static int cb_pcidas_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,	comedi_cmd *cmd);static void cb_pcidas_interrupt(int irq, void *d, struct pt_regs *regs);static void handle_ao_interrupt(comedi_device *dev, unsigned int status);static int cb_pcidas_cancel(comedi_device *dev, comedi_subdevice *s);static int cb_pcidas_ao_cancel(comedi_device *dev, comedi_subdevice *s);static void cb_pcidas_load_counters(comedi_device *dev, unsigned int *ns, int round_flags);static int eeprom_read_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int caldac_read_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int caldac_write_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int trimpot_read_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int cb_pcidas_trimpot_write( comedi_device *dev,	unsigned int channel, lsampl_t value );static int trimpot_write_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int dac08_read_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int dac08_write( comedi_device *dev, lsampl_t value );static int dac08_write_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data );static int caldac_8800_write(comedi_device *dev, unsigned int address, uint8_t value);static int trimpot_7376_write(comedi_device *dev, uint8_t value);static int trimpot_8402_write(comedi_device *dev, unsigned int channel, uint8_t value);static int nvram_read( comedi_device *dev, unsigned int address, uint8_t *data );/* * Attach is called by the Comedi core to configure the driver * for a particular board. */static int cb_pcidas_attach(comedi_device *dev, comedi_devconfig *it){	comedi_subdevice *s;	struct pci_dev* pcidev;	int index;	unsigned long s5933_config, control_status, adc_fifo,		pacer_counter_dio, ao_registers;	int err;	int i;	printk("comedi%d: cb_pcidas: ",dev->minor);/* * Allocate the private structure area. */	if(alloc_private(dev,sizeof(cb_pcidas_private))<0)		return -ENOMEM;/* * Probe the device to determine what device in the series it is. */	printk("\n");	pci_for_each_dev(pcidev)	{		// is it not a computer boards card?		if(pcidev->vendor != PCI_VENDOR_ID_CB)			continue;		// loop through cards supported by this driver		for(index = 0; index < N_BOARDS; index++)		{			if(cb_pcidas_boards[index].device_id != pcidev->device)				continue;			// was a particular bus/slot requested?			if(it->options[0] || it->options[1])			{				// are we on the wrong bus/slot?				if(pcidev->bus->number != it->options[0] ||				   PCI_SLOT(pcidev->devfn) != it->options[1])				{					continue;				}			}			devpriv->pci_dev = pcidev;			dev->board_ptr = cb_pcidas_boards + index;			goto found;		}	}	printk("No supported ComputerBoards/MeasurementComputing card found on "		"requested position\n");	return -EIO;found:	printk("Found %s on bus %i, slot %i\n", cb_pcidas_boards[index].name,		devpriv->pci_dev->bus->number, PCI_SLOT(devpriv->pci_dev->devfn));	/*	 * Initialize devpriv->control_status and devpriv->adc_fifo to point to	 * their base address.	 */	if(pci_enable_device(devpriv->pci_dev))		return -EIO;	s5933_config = pci_resource_start(devpriv->pci_dev, S5933_BADRINDEX); 	control_status = pci_resource_start(devpriv->pci_dev, CONT_STAT_BADRINDEX); 	adc_fifo = pci_resource_start(devpriv->pci_dev, ADC_FIFO_BADRINDEX); 	pacer_counter_dio = pci_resource_start(devpriv->pci_dev, PACER_BADRINDEX); 	ao_registers = pci_resource_start(devpriv->pci_dev, AO_BADRINDEX); 	// reserve io ports	err = 0;	if(check_region(s5933_config, AMCC_OP_REG_SIZE) < 0)		err++;	if(check_region(control_status, CONT_STAT_SIZE) < 0)		err++;	if(check_region(adc_fifo, ADC_FIFO_SIZE) < 0)		err++;	if(check_region(pacer_counter_dio, PACER_SIZE) < 0)		err++;	if(thisboard->ao_nchan)		if(check_region(ao_registers, AO_SIZE) < 0)			err++;	if(err)	{		printk(" I/O port conflict\n");		return -EIO;	}	request_region(s5933_config, AMCC_OP_REG_SIZE, "cb_pcidas");	devpriv->s5933_config = s5933_config;	request_region(control_status, CONT_STAT_SIZE, "cb_pcidas");	devpriv->control_status = control_status;	request_region(adc_fifo, ADC_FIFO_SIZE, "cb_pcidas");	devpriv->adc_fifo = adc_fifo;	request_region(pacer_counter_dio, PACER_SIZE, "cb_pcidas");	devpriv->pacer_counter_dio = pacer_counter_dio;	if(thisboard->ao_nchan)	{		request_region(ao_registers, AO_SIZE, "cb_pcidas");		devpriv->ao_registers = ao_registers;	}	// get irq	if(comedi_request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt, SA_SHIRQ, "cb_pcidas", dev ))	{		printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq);		return -EINVAL;	}	dev->irq = devpriv->pci_dev->irq;	//Initialize dev->board_name	dev->board_name = thisboard->name;/* * Allocate the subdevice structures. */	if(alloc_subdevices(dev, 7) < 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 | SDF_DIFF;	/* WARNING: Number of inputs in differential mode is ignored */	s->n_chan = thisboard->ai_se_chans;	s->len_chanlist = thisboard->ai_se_chans;	s->maxdata = (1 << thisboard->ai_bits) - 1;	s->range_table = thisboard->ranges;	s->insn_read = cb_pcidas_ai_rinsn;	s->insn_config = ai_config_insn;	s->do_cmd = cb_pcidas_ai_cmd;	s->do_cmdtest = cb_pcidas_ai_cmdtest;	s->cancel = cb_pcidas_cancel;	/* analog output subdevice */	s = dev->subdevices + 1;	if(thisboard->ao_nchan)	{		s->type = COMEDI_SUBD_AO;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;		s->n_chan = thisboard->ao_nchan;		// analog out resolution is the same as analog input resolution, so use ai_bits		s->maxdata = (1 << thisboard->ai_bits) - 1;		s->range_table = &cb_pcidas_ao_ranges;		s->insn_read = cb_pcidas_ao_readback_insn;		if(thisboard->has_ao_fifo)		{			dev->write_subdev = s;			s->insn_write = cb_pcidas_ao_fifo_winsn;			s->do_cmdtest = cb_pcidas_ao_cmdtest;			s->do_cmd = cb_pcidas_ao_cmd;			s->cancel = cb_pcidas_ao_cancel;		}else		{			s->insn_write = cb_pcidas_ao_nofifo_winsn;		}	}else	{		s->type = COMEDI_SUBD_UNUSED;	}	/* 8255 */	s = dev->subdevices + 2;	subdev_8255_init(dev, s, NULL,		(unsigned long)(devpriv->pacer_counter_dio + DIO_8255));	// serial EEPROM,	s = dev->subdevices + 3;	s->type = COMEDI_SUBD_MEMORY;	s->subdev_flags = SDF_READABLE | SDF_INTERNAL;	s->n_chan = 256;	s->maxdata = 0xff;	s->insn_read = eeprom_read_insn;	// 8800 caldac	s = dev->subdevices + 4;	s->type = COMEDI_SUBD_CALIB;	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;	s->n_chan = NUM_CHANNELS_8800;	s->maxdata = 0xff;	s->insn_read = caldac_read_insn;	s->insn_write = caldac_write_insn;	for( i = 0; i < s->n_chan; i++ )		caldac_8800_write( dev, i, s->maxdata / 2 );	// trim potentiometer	s = dev->subdevices + 5;	s->type = COMEDI_SUBD_CALIB;	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;	if( thisboard->trimpot == AD7376 )	{		s->n_chan = NUM_CHANNELS_7376;		s->maxdata = 0x7f;	}else	{		s->n_chan = NUM_CHANNELS_8402;		s->maxdata = 0xff;	}	s->insn_read = trimpot_read_insn;	s->insn_write = trimpot_write_insn;	for( i = 0; i < s->n_chan; i++ )		cb_pcidas_trimpot_write( dev, i, s->maxdata / 2 );	// dac08 caldac	s = dev->subdevices + 6;	if( thisboard->has_dac08 )	{		s->type = COMEDI_SUBD_CALIB;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;		s->n_chan = NUM_CHANNELS_DAC08;		s->insn_read = dac08_read_insn;		s->insn_write = dac08_write_insn;		s->maxdata = 0xff;		dac08_write( dev, s->maxdata / 2 );	}else		s->type = COMEDI_SUBD_UNUSED;	// make sure mailbox 4 is empty	inl(devpriv->s5933_config + AMCC_OP_REG_IMB4 );	/* Set bits to enable incoming mailbox interrupts on amcc s5933. */	devpriv->s5933_intcsr_bits = INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | INTCSR_INBOX_FULL_INT;	// clear and enable interrupt on amcc s5933	outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR);	return 1;}/* * cb_pcidas_detach is called to deconfigure a device.  It should deallocate * resources. * This function is also called when _attach() fails, so it should be * careful not to release resources that were not necessarily * allocated by _attach().  dev->private and dev->subdevices are * deallocated automatically by the core. */static int cb_pcidas_detach(comedi_device *dev){	printk("comedi%d: cb_pcidas: remove\n",dev->minor);	if(devpriv)	{		if(devpriv->s5933_config)		{			// disable and clear interrupts on amcc s5933			outl(INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR);#ifdef CB_PCIDAS_DEBUG			rt_printk("detaching, incsr is 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR));#endif			release_region(devpriv->s5933_config, AMCC_OP_REG_SIZE);		}		if(devpriv->control_status)			release_region(devpriv->control_status, CONT_STAT_SIZE);		if(devpriv->adc_fifo)			release_region(devpriv->adc_fifo, ADC_FIFO_SIZE);		if(devpriv->pacer_counter_dio)			release_region(devpriv->pacer_counter_dio, PACER_SIZE);		if(devpriv->ao_registers)			release_region(devpriv->ao_registers, AO_SIZE);	}	if(dev->irq)		comedi_free_irq(dev->irq, dev);	if(dev->subdevices)		subdev_8255_cleanup(dev,dev->subdevices + 2);	return 0;}/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */static int cb_pcidas_ai_rinsn(comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data){	int n,i;	unsigned int bits;	static const int timeout = 10000;	// enable calibration input if appropriate	if( insn->chanspec & CR_ALT_SOURCE )		outw( CAL_EN_BIT | CAL_SRC_BITS( devpriv->calibration_source ),			devpriv->control_status + CALIBRATION_REG);	else		outw( 0, devpriv->control_status + CALIBRATION_REG);	// set mux limits and gain	bits = BEGIN_SCAN(CR_CHAN(insn->chanspec)) |		END_SCAN(CR_CHAN(insn->chanspec)) |		GAIN_BITS(CR_RANGE(insn->chanspec));	// set unipolar/bipolar	if(CR_RANGE(insn->chanspec) & IS_UNIPOLAR)		bits |= UNIP;	// set singleended/differential	if(CR_AREF(insn->chanspec) != AREF_DIFF)		bits |= SE;	outw(bits, devpriv->control_status + ADCMUX_CONT);	/* clear fifo */	outw(0, devpriv->adc_fifo + ADCFIFOCLR);	/* convert n samples */	for (n = 0; n < insn->n; n++)	{		/* trigger conversion */		outw(0, devpriv->adc_fifo + ADCDATA);		/* wait for conversion to end */		/* return -ETIMEDOUT if there is a timeout */		for(i = 0; i < timeout; i++)		{			if (inw(devpriv->control_status + ADCMUX_CONT) & EOC)				break;		}		if(i == timeout)			return -ETIMEDOUT;		/* read data */		data[n] = inw(devpriv->adc_fifo + ADCDATA);	}	/* return the number of samples read/written */	return n;}static int ai_config_calibration_source( comedi_device *dev, lsampl_t *data ){	static const int num_calibration_sources = 8;	lsampl_t source = data[1];	if(source >= num_calibration_sources)	{		printk( "invalid calibration source: %i\n", source );		return -EINVAL;	}	devpriv->calibration_source = source;	return 2;}static int ai_config_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data){	int id = data[0];	switch( id )	{		case INSN_CONFIG_ALT_SOURCE:			return ai_config_calibration_source( dev, data );			break;		default:			return -EINVAL;			break;	}	return -EINVAL;}// analog output insn for pcidas-1000 and 1200 seriesstatic int cb_pcidas_ao_nofifo_winsn(comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data){	int channel;	unsigned long flags;	// set channel and range	channel = CR_CHAN(insn->chanspec);	comedi_spin_lock_irqsave( &dev->spinlock, flags );	devpriv->ao_control_bits &= ~DAC_MODE_UPDATE_BOTH & ~DAC_RANGE_MASK( channel );	devpriv->ao_control_bits |= DACEN | DAC_RANGE( channel, CR_RANGE( insn->chanspec ) );	outw( devpriv->ao_control_bits, devpriv->control_status + DAC_CSR );	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// remember value for readback	devpriv->ao_value[channel] = data[0];	// send data	outw(data[0], devpriv->ao_registers + DAC_DATA_REG(channel));	return 1;}// analog output insn for pcidas-1602 seriesstatic int cb_pcidas_ao_fifo_winsn(comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data){	int bits, channel;	// clear dac fifo	outw(0, devpriv->ao_registers + DACFIFOCLR);	// set channel and range	channel = CR_CHAN(insn->chanspec);	bits = DACEN;	bits |= DAC_RANGE(channel, CR_RANGE(insn->chanspec));	bits |= DAC_CHAN_EN(channel);	bits |= DAC_START;	// not sure if this is necessary	outw(bits, devpriv->control_status + DAC_CSR);	// remember value for readback	devpriv->ao_value[channel] = data[0];	// send data	outw(data[0], devpriv->ao_registers + DACDATA);	return 1;}// analog output readback insn// XXX loses track of analog output value back after an analog ouput command is executedstatic int cb_pcidas_ao_readback_insn(comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data){	data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];	return 1;}static int eeprom_read_insn( comedi_device *dev, comedi_subdevice *s,	comedi_insn *insn, lsampl_t *data ){	uint8_t nvram_data;	int retval;	retval = nvram_read( dev, CR_CHAN( insn->chanspec ), &nvram_data );

⌨️ 快捷键说明

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