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

📄 cb_pcidas64.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
static void disable_plx_interrupts( comedi_device *dev ){	priv(dev)->plx_intcsr_bits = 0;	writel(priv(dev)->plx_intcsr_bits, priv(dev)->plx9080_iobase + PLX_INTRCS_REG);}static void init_stc_registers( comedi_device *dev ){	uint16_t bits;	unsigned long flags;	comedi_spin_lock_irqsave( &dev->spinlock, flags );	// bit should be set for 6025, although docs say boards with <= 16 chans should be cleared XXX	if( 1 )		priv(dev)->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT;	writew( priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG );	bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT;	if(board(dev)->layout == LAYOUT_4020)		bits |= INTERNAL_CLOCK_4020_BITS;	priv(dev)->hw_config_bits |= bits;	writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG);	writew(0, priv(dev)->main_iobase + DAQ_SYNC_REG);	writew(0, priv(dev)->main_iobase + CALIBRATION_REG);	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// set fifos to maximum size	priv(dev)->fifo_size_bits |= DAC_FIFO_BITS;	set_ai_fifo_segment_length( dev, board(dev)->ai_fifo->max_segment_length );};/* * Attach is called by the Comedi core to configure the driver * for a particular board. */static int attach(comedi_device *dev, comedi_devconfig *it){	struct pci_dev* pcidev;	int index;	uint32_t local_range, local_decode;	int retval;	printk("comedi%d: cb_pcidas64\n",dev->minor);/* * Allocate the private structure area. */	if(alloc_private(dev,sizeof(pcidas64_private)) < 0)		return -ENOMEM;/* * Probe the device to determine what device in the series it is. */	pci_for_each_dev( pcidev )	{		// is it not a computer boards card?		if( pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS )			continue;		// loop through cards supported by this driver		for(index = 0; index < num_boards(); index++)		{			if( pcidas64_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;				}			}			dev->board_ptr = pcidas64_boards + index;			break;		}		if( dev->board_ptr ) break;	}	if( dev->board_ptr == NULL )	{		printk("No supported ComputerBoards/MeasurementComputing card found\n");		return -EIO;	}	printk("Found %s on bus %i, slot %i\n", board(dev)->name,		pcidev->bus->number, PCI_SLOT(pcidev->devfn));	if( pci_enable_device( pcidev ) )		return -EIO;	pci_set_master( pcidev );	priv(dev)->hw_dev = pcidev;	//Initialize dev->board_name	dev->board_name = board(dev)->name;	if( pci_request_regions( pcidev, driver_cb_pcidas.driver_name ) )	{		/* Couldn't allocate io space */		printk(KERN_WARNING " failed to allocate io memory\n");		return -EIO;	}	priv(dev)->plx9080_phys_iobase = pci_resource_start(pcidev, PLX9080_BADDRINDEX);	priv(dev)->main_phys_iobase = pci_resource_start(pcidev, MAIN_BADDRINDEX);	priv(dev)->dio_counter_phys_iobase = pci_resource_start(pcidev, DIO_COUNTER_BADDRINDEX);	// remap, won't work with 2.0 kernels but who cares	priv(dev)->plx9080_iobase = (unsigned long)ioremap(priv(dev)->plx9080_phys_iobase,		pci_resource_len(pcidev, PLX9080_BADDRINDEX));	priv(dev)->main_iobase = (unsigned long)ioremap(priv(dev)->main_phys_iobase,		pci_resource_len(pcidev, MAIN_BADDRINDEX));	priv(dev)->dio_counter_iobase = (unsigned long)ioremap(priv(dev)->dio_counter_phys_iobase,		pci_resource_len(pcidev, DIO_COUNTER_BADDRINDEX));	DEBUG_PRINT(" plx9080 remapped to 0x%lx\n", priv(dev)->plx9080_iobase);	DEBUG_PRINT(" main remapped to 0x%lx\n", priv(dev)->main_iobase);	DEBUG_PRINT(" diocounter remapped to 0x%lx\n", priv(dev)->dio_counter_iobase);	// get irq	if(comedi_request_irq(pcidev->irq, handle_interrupt, SA_SHIRQ, "cb_pcidas64", dev ))	{		printk(" unable to allocate irq %d\n", pcidev->irq);		return -EINVAL;	}	dev->irq = pcidev->irq;	printk(" irq %i\n", dev->irq);	// figure out what local addresses are	local_range = readl(priv(dev)->plx9080_iobase + PLX_LAS0RNG_REG) & LRNG_MEM_MASK;	local_decode = readl(priv(dev)->plx9080_iobase + PLX_LAS0MAP_REG) & local_range & LMAP_MEM_MASK ;	priv(dev)->local0_iobase = (priv(dev)->main_phys_iobase & ~local_range) | local_decode;	local_range = readl(priv(dev)->plx9080_iobase + PLX_LAS1RNG_REG) & LRNG_MEM_MASK;	local_decode = readl(priv(dev)->plx9080_iobase + PLX_LAS1MAP_REG) & local_range & LMAP_MEM_MASK ;	priv(dev)->local1_iobase = (priv(dev)->dio_counter_phys_iobase & ~local_range) | local_decode;	DEBUG_PRINT(" local 0 io addr 0x%x\n", priv(dev)->local0_iobase);	DEBUG_PRINT(" local 1 io addr 0x%x\n", priv(dev)->local1_iobase);	priv(dev)->hw_revision = hw_revision( dev, readw(priv(dev)->main_iobase + HW_STATUS_REG ) );	printk(" stc hardware revision %i\n", priv(dev)->hw_revision);	init_plx9080(dev);	// alocate pci dma buffers	for(index = 0; index < DMA_RING_COUNT; index++)	{		priv(dev)->ai_buffer[index] =			pci_alloc_consistent(priv(dev)->hw_dev, DMA_BUFFER_SIZE, &priv(dev)->ai_buffer_phys_addr[index]);	}	// allocate dma descriptors	priv(dev)->dma_desc =		pci_alloc_consistent(priv(dev)->hw_dev, sizeof(struct plx_dma_desc) * DMA_RING_COUNT,		&priv(dev)->dma_desc_phys_addr);	// initialize dma descriptors	for(index = 0; index < DMA_RING_COUNT; index++)	{		priv(dev)->dma_desc[index].pci_start_addr = priv(dev)->ai_buffer_phys_addr[index];		if(board(dev)->layout == LAYOUT_4020)			priv(dev)->dma_desc[index].local_start_addr = priv(dev)->local1_iobase + ADC_FIFO_REG;		else			priv(dev)->dma_desc[index].local_start_addr = priv(dev)->local0_iobase + ADC_FIFO_REG;		priv(dev)->dma_desc[index].transfer_size = 0;		priv(dev)->dma_desc[index].next = (priv(dev)->dma_desc_phys_addr + ((index + 1) % (DMA_RING_COUNT)) * sizeof(priv(dev)->dma_desc[0])) |			PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;	}	retval = setup_subdevices(dev);	if(retval < 0)	{		return retval;	}	init_stc_registers( dev );	return 0;}/* * _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 detach(comedi_device *dev){	unsigned int i;	printk("comedi%d: cb_pcidas: remove\n",dev->minor);	if(dev->irq)		comedi_free_irq(dev->irq, dev);	if(priv(dev))	{		if( priv(dev)->hw_dev )		{			if(priv(dev)->plx9080_iobase)			{				disable_plx_interrupts( dev );				iounmap((void*)priv(dev)->plx9080_iobase);			}			if(priv(dev)->main_iobase)				iounmap((void*)priv(dev)->main_iobase);			if(priv(dev)->dio_counter_iobase)				iounmap((void*)priv(dev)->dio_counter_iobase);			if(priv(dev)->plx9080_phys_iobase ||				priv(dev)->main_phys_iobase || priv(dev)->dio_counter_phys_iobase)				pci_release_regions( priv(dev)->hw_dev );			// free pci dma buffers			for(i = 0; i < DMA_RING_COUNT; i++)			{				if( priv(dev)->ai_buffer[i] )					pci_free_consistent( priv(dev)->hw_dev, DMA_BUFFER_SIZE,						priv(dev)->ai_buffer[i], priv(dev)->ai_buffer_phys_addr[i] );			}			// free dma descriptors			if(priv(dev)->dma_desc)				pci_free_consistent( priv(dev)->hw_dev, sizeof( struct plx_dma_desc ) * DMA_RING_COUNT,					priv(dev)->dma_desc, priv(dev)->dma_desc_phys_addr );			pci_disable_device( priv(dev)->hw_dev );		}	}	if(dev->subdevices)		subdev_8255_cleanup(dev,dev->subdevices + 4);	return 0;}static int ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){	unsigned int bits = 0, n, i;	const int timeout = 100;	unsigned int channel, range, aref;	unsigned long flags;	DEBUG_PRINT("chanspec 0x%x\n", insn->chanspec);	channel = CR_CHAN(insn->chanspec);	range = CR_RANGE(insn->chanspec);	aref = CR_AREF(insn->chanspec);	// disable card's analog input interrupt sources and pacing	// 4020 generates dac done interrupts even though they are disabled	disable_ai_pacing( dev );	comedi_spin_lock_irqsave( &dev->spinlock, flags );	if( insn->chanspec & CR_DITHER )		priv(dev)->adc_control1_bits |= ADC_DITHER_BIT;	else		priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT;	writew( priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG );	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	if(board(dev)->layout != LAYOUT_4020)	{		// use internal queue		priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT;		writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG);		// load internal queue		bits = 0;		// set gain		bits |= ai_range_bits_6xxx( dev, CR_RANGE(insn->chanspec) );		// set single-ended / differential		if( ( board(dev)->layout == LAYOUT_64XX && aref != AREF_DIFF ) ||			( board(dev)->layout == LAYOUT_60XX && aref == AREF_DIFF ) )			bits |= ADC_SE_DIFF_BIT;		if( aref == AREF_COMMON)			bits |= ADC_COMMON_BIT;		// ALT_SOURCE is internal calibration reference		if(insn->chanspec & CR_ALT_SOURCE)		{			unsigned int cal_en_bit;			DEBUG_PRINT("reading calibration source\n");			if( board(dev)->layout == LAYOUT_60XX)				cal_en_bit = CAL_EN_60XX_BIT;			else				cal_en_bit = CAL_EN_64XX_BIT;			// select internal reference source to connect to channel 0			writew(cal_en_bit | adc_src_bits( priv(dev)->calibration_source ),				priv(dev)->main_iobase + CALIBRATION_REG);		} else		{			// make sure internal calibration source is turned off			writew(0, priv(dev)->main_iobase + CALIBRATION_REG);		}		bits |= adc_chan_bits( channel );		// set start channel, and rest of settings		writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);		// set stop channel		writew( adc_chan_bits( channel ), priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG );	}else	{		uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits;		priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;		if(insn->chanspec & CR_ALT_SOURCE)		{			DEBUG_PRINT("reading calibration source\n");			priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits( priv(dev)->calibration_source );		} else		{	//select BNC inputs			priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits( 4 );		}		// select range		if( ai_range_bits_6xxx( dev, range ) )			priv(dev)->i2c_cal_range_bits |= attenuate_bit( channel );		else			priv(dev)->i2c_cal_range_bits &= ~attenuate_bit( channel );		// update calibration/range i2c register only if necessary, as it is very slow		if(old_cal_range_bits != priv(dev)->i2c_cal_range_bits)		{			uint8_t i2c_data = priv(dev)->i2c_cal_range_bits;			i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data, sizeof(i2c_data));		}		/* 4020 manual asks that sample interval register to be set before writing to convert register.		 * Using somewhat arbitrary setting of 4 master clock ticks = 0.1 usec */		writew(0, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);		writew(2, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);	}	for(n = 0; n < insn->n; n++)	{		// clear adc buffer (inside loop for 4020 sake)		writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG);		/* trigger conversion, bits sent only matter for 4020 */		writew( adc_convert_chan_4020_bits( CR_CHAN( insn->chanspec ) ),			priv(dev)->main_iobase + ADC_CONVERT_REG );		// wait for data		for(i = 0; i < timeout; i++)		{			bits = readw(priv(dev)->main_iobase + HW_STATUS_REG);			DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits( bits ) );			if(board(dev)->layout == LAYOUT_4020)			{				if( readw( priv(dev)->main_iobase + ADC_WRITE_PNTR_REG ) )					break;			}else			{				if( pipe_full_bits( bits ) )					break;			}			comedi_udelay(1);		}		DEBUG_PRINT(" looped %i times waiting for data\n", i);		if(i == timeout)		{			comedi_error(dev, " analog input read insn timed out");			rt_printk(" status 0x%x\n", bits);			return -ETIME;		}		if(board(dev)->layout == LAYOUT_4020)			data[n] = readl(priv(dev)->dio_counter_iobase + ADC_FIFO_REG) & 0xffff;		else			data[n] = readw(priv(dev)->main_iobase + PIPE1_READ_REG);	}	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;	}	DEBUG_PRINT("setting calibration source to %i\n", source);	priv(dev)->calibration_source = source;	return 2;}static int ai_config_block_size( comedi_device *dev, lsampl_t *data ){	int fifo_size;	const hw_fifo_info_t *const fifo = board(dev)->ai_fifo;	unsigned int block_size, requested_block_size;	int retval;	static const int bytes_per_sample = 2;	requested_block_size = data[ 1 ];	if( requested_block_size )	{		fifo_size = requested_block_size * fifo->num_segments / bytes_per_sample;		retval = set_ai_fifo_size( dev, fifo_size );		if( retval < 0 ) return retval;	}	block_size = ai_fifo_size( dev ) / fifo->num_segments * bytes_per_sample;	data[ 1 ] = block_size;	return 2;}static int ai_config_master_clock_4020( comedi_device *dev, lsampl_t *data ){	unsigned int divisor = data[4];	int retval = 0;	if( divisor < 2 )	{		divisor = 2;		retval = -EAGAIN;	}	switch( data[1] )	{		case COMEDI_EV_SCAN_BEGIN:			priv(dev)->ext_clock.scan_divisor = divisor;			priv(dev)->ext_clock.chanspec = data[2];			break;		default:			return -EINVAL;			break;	}	data[4] = divisor;	return retval ? retval : 5;}// XXX could add support for 60xx seriesstatic int ai_config_master_clock( comedi_device *dev, lsampl_t *data ){	switch( board(dev)->layout  )	{		case LAYOUT_4020:			return ai_config_master_clock_4020( dev, data );			break;		default:			return -EINVAL;			break;	}	return -EINVAL;}

⌨️ 快捷键说明

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