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

📄 ni_labpc.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		has_ao:	1,		read_byte:	labpc_inb,		write_byte:	labpc_outb,		ai_range_table:	&range_labpc_plus_ai,		ai_range_code: labpc_plus_ai_gain_bits,		ai_range_is_unipolar: labpc_plus_is_unipolar,		ai_scan_up: 0,	},	{		name:	"pci-1200",		device_id:	0x161,		ai_speed:	10000,		bustype:	pci_bustype,		register_layout:	labpc_1200_layout,		has_ao:	1,		read_byte:	labpc_readb,		write_byte:	labpc_writeb,		ai_range_table:	&range_labpc_1200_ai,		ai_range_code: labpc_1200_ai_gain_bits,		ai_range_is_unipolar: labpc_1200_is_unipolar,		ai_scan_up: 1,	},};/* * Useful for shorthand access to the particular board structure */#define thisboard ((labpc_board *)dev->board_ptr)static const int dma_buffer_size = 0xff00;	// size in bytes of dma bufferstatic const int sample_size = 2;	// 2 bytes per sampletypedef struct{	struct mite_struct *mite;	// for mite chip on pci-1200	volatile unsigned long long count;  /* number of data points left to be taken */	unsigned int ao_value[NUM_AO_CHAN];	// software copy of analog output values	// software copys of bits written to command registers	volatile unsigned int command1_bits;	volatile unsigned int command2_bits;	volatile unsigned int command3_bits;	volatile unsigned int command4_bits;	volatile unsigned int command5_bits;	volatile unsigned int command6_bits;	// store last read of board status registers	volatile unsigned int status1_bits;	volatile unsigned int status2_bits;	unsigned int divisor_a0;	/* value to load into board's counter a0 (conversion pacing) for timed conversions */	unsigned int divisor_b0; 	/* value to load into board's counter b0 (master) for timed conversions */	unsigned int divisor_b1; 	/* value to load into board's counter b1 (scan pacing) for timed conversions */	unsigned int dma_chan;	// dma channel to use	u16 *dma_buffer;	// buffer ai will dma into	unsigned int dma_transfer_size;	// transfer size in bytes for current transfer	enum transfer_type current_transfer;	// we are using dma/fifo-half-full/etc.	unsigned int eeprom_data[EEPROM_SIZE];	// stores contents of board's eeprom	unsigned int caldac[16];	// stores settings of calibration dacs}labpc_private;#define devpriv ((labpc_private *)dev->private)static comedi_driver driver_labpc={	driver_name:	"ni_labpc",	module:		THIS_MODULE,	attach:		labpc_attach,	detach:		labpc_detach,	num_names:	sizeof(labpc_boards) / sizeof(labpc_board),	board_name:	(char **)labpc_boards,	offset:		sizeof(labpc_board),};static struct pci_device_id labpc_pci_table[] __devinitdata = {	{ PCI_VENDOR_ID_NATINST, 0x161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0 }};MODULE_DEVICE_TABLE(pci, labpc_pci_table);static int labpc_attach(comedi_device *dev, comedi_devconfig *it){	comedi_subdevice *s;	int iobase = 0;	int irq = 0;	int dma_chan = 0;	int lsb, msb;	int i;	unsigned long flags, isr_flags;	int ret;#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)	dev_link_t *link;#endif	/* allocate and initialize dev->private */	if(alloc_private(dev, sizeof(labpc_private)) < 0)		return -ENOMEM;	// get base address, irq etc. based on bustype	switch(thisboard->bustype)	{		case isa_bustype:			iobase = it->options[0];			irq = it->options[1];			dma_chan = it->options[2];			break;		case pci_bustype:			devpriv->mite = labpc_find_device(it->options[0], it->options[1]);			if(devpriv->mite == NULL)			{				return -EIO;			}			if(thisboard->device_id != mite_device_id(devpriv->mite))			{	// this should never happen since this driver only supports one type of pci board				printk("bug! mite device id does not match boardtype definition\n");				return -EINVAL;			}			ret = mite_setup(devpriv->mite);			if(ret < 0) return ret;			iobase = mite_iobase(devpriv->mite);			irq = mite_irq(devpriv->mite);			break;		case pcmcia_bustype:#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)			link = pcmcia_dev_list; /* XXX hack */			if(!link) return -EIO;			iobase = link->io.BasePort1;			irq = link->irq.AssignedIRQ;#else			printk(" driver was not compiled with pcmcia support\n");			return -EINVAL;#endif // CONFIG_PCMCIA			break;		default:			printk("bug! couldn't determine board type\n");\			return -EINVAL;			break;	}	printk("comedi%d: ni_labpc: %s, io 0x%x", dev->minor, thisboard->name, iobase);	if(irq)	{		printk(", irq %i", irq);	}	if(dma_chan)	{		printk(", dma %i", dma_chan);	}	printk("\n");	if(iobase == 0)	{		printk("io base address is zero!\n");		return -EINVAL;	}	// request io regions for isa boards	if(thisboard->bustype == isa_bustype)	{		/* check if io addresses are available */		if(check_region(iobase, LABPC_SIZE) < 0)		{			printk("I/O port conflict\n");			return -EIO;		}		request_region(iobase, LABPC_SIZE, driver_labpc.driver_name);	}	dev->iobase = iobase;	// initialize board's command registers	thisboard->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);	thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);	thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);	thisboard->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);	if(thisboard->register_layout == labpc_1200_layout)	{		thisboard->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);		thisboard->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG);	}	/* grab our IRQ */	if(irq < 0)	{		printk("irq out of range\n");		return -EINVAL;	}	if(irq)	{		isr_flags = 0;		if((thisboard->bustype == pci_bustype)#if 0				// I'm fairly sure the daqcard-1200 interrupt cannot be shared				|| (thisboard->bustype == pcmcia_bustype)#endif				)			isr_flags |= SA_SHIRQ;		if(comedi_request_irq( irq, labpc_interrupt, isr_flags, driver_labpc.driver_name, dev))		{			printk( "unable to allocate irq %d\n", irq);			return -EINVAL;		}	}	dev->irq = irq;	// grab dma channel	if(dma_chan < 0 || dma_chan > 3)	{		printk(" invalid dma channel\n");		return -EINVAL;	}else if(dma_chan)	{		// allocate dma buffer		devpriv->dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);		if(devpriv->dma_buffer == NULL)		{			printk(" failed to allocate dma buffer\n");			return -ENOMEM;		}		if(request_dma(dma_chan, driver_labpc.driver_name))		{			printk(" failed to allocate dma channel %i\n", dma_chan);			return -EINVAL;		}		devpriv->dma_chan = dma_chan;		flags = claim_dma_lock();		disable_dma(devpriv->dma_chan);		set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);		release_dma_lock(flags);	}	dev->board_name = thisboard->name;	if(alloc_subdevices(dev, 5) < 0)		return -ENOMEM;	/* analog input subdevice */	s = dev->subdevices + 0;	dev->read_subdev = s;	s->type = COMEDI_SUBD_AI;	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;	s->n_chan = 8;	s->len_chanlist = 8;	s->maxdata = (1 << 12) - 1;	// 12 bit resolution	s->range_table = thisboard->ai_range_table;	s->do_cmd = labpc_ai_cmd;	s->do_cmdtest = labpc_ai_cmdtest;	s->insn_read = labpc_ai_rinsn;	s->cancel = labpc_cancel;	/* analog output */	s = dev->subdevices + 1;	if(thisboard->has_ao)	{/* Could provide command support, except it only has a one sample * hardware buffer for analog output and no underrun flag. */		s->type=COMEDI_SUBD_AO;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;		s->n_chan = NUM_AO_CHAN;		s->maxdata = (1 << 12) - 1;	// 12 bit resolution		s->range_table = &range_labpc_ao;		s->insn_read = labpc_ao_rinsn;		s->insn_write = labpc_ao_winsn;		/* initialize analog outputs to a known value */		for(i = 0; i < s->n_chan; i++)		{			devpriv->ao_value[i] = s->maxdata / 2;			lsb = devpriv->ao_value[i] & 0xff;			msb = (devpriv->ao_value[i] >> 8) & 0xff;			thisboard->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));			thisboard->write_byte(msb, dev->iobase + DAC_MSB_REG(i));		}	}else	{		s->type = COMEDI_SUBD_UNUSED;	}	/* 8255 dio */	s = dev->subdevices + 2;	// if board uses io memory we have to give a custom callback function to the 8255 driver	if(thisboard->write_byte == labpc_writeb)		subdev_8255_init(dev, s, labpc_dio_mem_callback, (unsigned long)(dev->iobase + DIO_BASE_REG));	else		subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);	// calibration subdevices for boards that have one	s = dev->subdevices + 3;	if(thisboard->register_layout == labpc_1200_layout)	{		s->type=COMEDI_SUBD_CALIB;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;		s->n_chan = 16;		s->maxdata = 0xff;		s->insn_read = labpc_calib_read_insn;		s->insn_write = labpc_calib_write_insn;		for( i = 0; i < s->n_chan; i++ )			write_caldac( dev, i, s->maxdata / 2 );	}else		s->type = COMEDI_SUBD_UNUSED;	/* EEPROM */	s = dev->subdevices + 4;	if(thisboard->register_layout == labpc_1200_layout)	{		s->type = COMEDI_SUBD_MEMORY;		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;		s->n_chan = EEPROM_SIZE;		s->maxdata = 0xff;		s->insn_read = labpc_eeprom_read_insn;		s->insn_write = labpc_eeprom_write_insn;		for(i = 0; i < EEPROM_SIZE; i++)		{			devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);		}#ifdef LABPC_DEBUG		printk(" eeprom:");		for(i = 0; i < EEPROM_SIZE; i++)		{			printk(" %i:0x%x ", i, devpriv->eeprom_data[i]);		}		printk("\n");#endif	}else		s->type = COMEDI_SUBD_UNUSED;	return 0;};// adapted from ni_pcimio for finding mite based boards (pc-1200)static struct mite_struct* labpc_find_device(int bus, int slot){	struct mite_struct *mite;	int i;	for(mite = mite_devices; mite; mite = mite->next)	{		if(mite->used) continue;		// if bus/slot are specified then make sure we have the right bus/slot		if(bus || slot)		{			if(bus != mite->pcidev->bus->number || slot != PCI_SLOT(mite->pcidev->devfn)) continue;		}		for(i = 0; i < driver_labpc.num_names; i++)		{			if(labpc_boards[i].bustype != pci_bustype) continue;			if(mite_device_id(mite) == labpc_boards[i].device_id)			{				 return mite;			 }		}	}	printk("no device found\n");	mite_list_devices();	return NULL;}static int labpc_detach(comedi_device *dev){	printk("comedi%d: ni_labpc: remove\n", dev->minor);	if(dev->subdevices)		subdev_8255_cleanup(dev,dev->subdevices + 2);	/* only free stuff if it has been allocated by _attach */	if(devpriv->dma_buffer)		kfree(devpriv->dma_buffer);	if(devpriv->dma_chan)		free_dma(devpriv->dma_chan);	if(dev->irq)		comedi_free_irq(dev->irq, dev);	if(thisboard->bustype == isa_bustype &&		dev->iobase)		release_region(dev->iobase, LABPC_SIZE);	if( devpriv->mite )		mite_unsetup( devpriv->mite );	return 0;};static void labpc_clear_adc_fifo( const comedi_device *dev ){	thisboard->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);	thisboard->read_byte(dev->iobase + ADC_FIFO_REG);	thisboard->read_byte(dev->iobase + ADC_FIFO_REG);}static int labpc_cancel(comedi_device *dev, comedi_subdevice *s){	unsigned long flags;	comedi_spin_lock_irqsave( &dev->spinlock, flags );	devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;	thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	devpriv->command3_bits = 0;	thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);	return 0;}static enum scan_mode labpc_ai_scan_mode( const comedi_cmd *cmd ){	if( cmd->chanlist_len == 1 )		return MODE_SINGLE_CHAN;	if( CR_CHAN( cmd->chanlist[0] ) == CR_CHAN( cmd->chanlist[1] ) )		return MODE_SINGLE_CHAN_INTERVAL;	if( CR_CHAN( cmd->chanlist[0] ) < CR_CHAN( cmd->chanlist[1] ) )		return MODE_MULT_CHAN_UP;	if( CR_CHAN( cmd->chanlist[0] ) > CR_CHAN( cmd->chanlist[1] ) )		return MODE_MULT_CHAN_DOWN;	rt_printk( "ni_labpc: bug! this should never happen\n");	return 0;}static int labpc_ai_chanlist_invalid( const comedi_device *dev,	const comedi_cmd *cmd ){	int mode, channel, range, aref, i;	if( cmd->chanlist == NULL ) return 0;	mode = labpc_ai_scan_mode( cmd );	if( mode == MODE_SINGLE_CHAN ) return 0;	if( mode == MODE_SINGLE_CHAN_INTERVAL )	{		if( cmd->chanlist_len > 0xff )		{			comedi_error(dev, "ni_labpc: chanlist too long for single channel interval mode\n");			return 1;		}	}	channel = CR_CHAN( cmd->chanlist[ 0 ] );

⌨️ 快捷键说明

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