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

📄 cb_pcidda.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    cb_pcidda.c    This intends to be a driver for the ComputerBoards / MeasurementComputing    PCI-DDA series.	 Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com>    Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//*Driver: cb_pcidda.oDescription: ComputerBoards/MeasurementComputing PCI-DDA seriesAuthor: Ivan Martinez <ivanmr@altavista.com>, Frank Mori Hess <fmhess@users.sourceforge.net>Status: Supports 08/16, 04/16, 02/16, 08/12, 04/12, and 02/12Devices: [Measurement Computing] PCI-DDA08/12 (cb_pcidda), PCI-DDA04/12,  PCI-DDA02/12, PCI-DDA08/16, PCI-DDA04/16, PCI-DDA02/16Configuration options:  [0] - PCI bus of device (optional)  [1] - PCI slot of device (optional)  If bus/slot is not specified, the first available PCI  device will be used.Only simple analog output writing is supported.So far it has only been tested with:  - PCI-DDA08/12Please report sucess/failure with other different cards to<comedi@comedi.org>.*/#include <linux/comedidev.h>#include <linux/pci.h>#include "8255.h"#define PCI_VENDOR_ID_CB	0x1307	// PCI vendor number of ComputerBoards#define N_BOARDS	10	// Number of boards in cb_pcidda_boards#define EEPROM_SIZE	128	// number of entries in eeprom#define MAX_AO_CHANNELS 8	// maximum number of ao channels for supported boards/* PCI-DDA base addresses */#define DIGITALIO_BADRINDEX	2	// DIGITAL I/O is pci_dev->resource[2]#define DIGITALIO_SIZE 8	// DIGITAL I/O uses 8 I/O port addresses#define DAC_BADRINDEX	3	// DAC is pci_dev->resource[3]/* Digital I/O registers */#define PORT1A 0	// PORT 1A DATA#define PORT1B 1	// PORT 1B DATA#define PORT1C 2	// PORT 1C DATA#define CONTROL1 3	// CONTROL REGISTER 1#define PORT2A 4	// PORT 2A DATA#define PORT2B 5	// PORT 2B DATA#define PORT2C 6	// PORT 2C DATA#define CONTROL2 7	// CONTROL REGISTER 2/* DAC registers */#define DACONTROL	0	// D/A CONTROL REGISTER#define	SU	0000001	// Simultaneous update enabled#define NOSU	0000000	// Simultaneous update disabled#define	ENABLEDAC	0000002	// Enable specified DAC#define	DISABLEDAC	0000000	// Disable specified DAC#define RANGE2V5	0000000	// 2.5V#define RANGE5V	0000200	// 5V#define RANGE10V	0000300	// 10V#define UNIP	0000400	// Unipolar outputs#define BIP	0000000	// Bipolar outputs#define DACALIBRATION1	4	// D/A CALIBRATION REGISTER 1//write bits#define	SERIAL_IN_BIT	0x1	// serial data input for eeprom, caldacs, reference dac#define	CAL_CHANNEL_MASK	(0x7 << 1)#define	CAL_CHANNEL_BITS(channel)	(((channel) << 1) & CAL_CHANNEL_MASK)//read bits#define	CAL_COUNTER_MASK	0x1f#define	CAL_COUNTER_OVERFLOW_BIT	0x20	// calibration counter overflow status bit#define	AO_BELOW_REF_BIT	0x40	// analog output is less than reference dac voltage#define	SERIAL_OUT_BIT	0x80	// serial data out, for reading from eeprom#define DACALIBRATION2	6 // D/A CALIBRATION REGISTER 2#define	SELECT_EEPROM_BIT	0x1	// send serial data in to eeprom#define	DESELECT_REF_DAC_BIT	0x2	// don't send serial data to MAX542 reference dac#define	DESELECT_CALDAC_BIT(n)	(0x4 << (n))	// don't send serial data to caldac n#define	DUMMY_BIT	0x40	// manual says to set this bit with no explanation#define DADATA	8	// FIRST D/A DATA REGISTER (0)static comedi_lrange cb_pcidda_ranges ={	6,	{		BIP_RANGE(10),		BIP_RANGE(5),		BIP_RANGE(2.5),		UNI_RANGE(10),		UNI_RANGE(5),		UNI_RANGE(2.5),	}};/* * Board descriptions for two imaginary boards.  Describing the * boards in this way is optional, and completely driver-dependent. * Some drivers use arrays such as this, other do not. */typedef struct cb_pcidda_board_struct{	char *name;	char status;		// Driver status:				// 0 - tested				// 1 - manual read, not tested				// 2 - manual not read	unsigned short device_id;	int ao_chans;	int ao_bits;	comedi_lrange *ranges;} cb_pcidda_board;static cb_pcidda_board cb_pcidda_boards[] ={	{		name:		"pci-dda02/12",		status:		1,		device_id:	0x20,		ao_chans:	2,		ao_bits:	12,		ranges:	&cb_pcidda_ranges,	},	{		name:		"pci-dda04/12",		status:		1,		device_id:	0x21,		ao_chans:	4,		ao_bits:	12,		ranges:	&cb_pcidda_ranges,	},	{		name:		"pci-dda08/12",		status:		0,		device_id:	0x22,		ao_chans:	8,		ao_bits:	12,		ranges:	&cb_pcidda_ranges,	},	{		name:		"pci-dda02/16",		status:		2,		device_id:	0x23,		ao_chans:	2,		ao_bits:	16,		ranges:	&cb_pcidda_ranges,	},	{		name:		"pci-dda04/16",		status:		2,		device_id:	0x24,		ao_chans:	4,		ao_bits:	16,		ranges:	&cb_pcidda_ranges,	},	{		name:		"pci-dda08/16",		status:		0,		device_id:	0x25,		ao_chans:	8,		ao_bits:	16,		ranges:	&cb_pcidda_ranges,	},};static struct pci_device_id cb_pcidda_pci_table[] __devinitdata = {	{ PCI_VENDOR_ID_CB, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_CB, 0x0021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_CB, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_CB, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_CB, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_CB, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0 }};MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);/* * Useful for shorthand access to the particular board structure */#define thisboard ((cb_pcidda_board *)dev->board_ptr)/* this structure is for data unique to this hardware driver.  If   several hardware drivers keep similar information in this structure,   feel free to suggest moving the variable to the comedi_device struct.  */typedef struct{	int data;	/* would be useful for a PCI device */	struct pci_dev *pci_dev;	unsigned long digitalio;	unsigned long dac;	//unsigned long control_status;	//unsigned long adc_fifo;	unsigned int dac_cal1_bits;	// bits last written to da calibration register 1	unsigned int ao_range[MAX_AO_CHANNELS];	// current range settings for output channels	u16 eeprom_data[EEPROM_SIZE];	// software copy of board's eeprom} cb_pcidda_private;/* * most drivers define the following macro to make it easy to * access the private structure. */#define devpriv ((cb_pcidda_private *)dev->private)static int cb_pcidda_attach(comedi_device *dev,comedi_devconfig *it);static int cb_pcidda_detach(comedi_device *dev);//static int cb_pcidda_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int cb_pcidda_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);//static int cb_pcidda_ai_cmd(comedi_device *dev,comedi_subdevice *s);static int cb_pcidda_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,	comedi_cmd *cmd);static int cb_pcidda_ns_to_timer(unsigned int *ns,int round);static unsigned int cb_pcidda_serial_in(comedi_device *dev);static void cb_pcidda_serial_out(comedi_device *dev, unsigned int value, unsigned int num_bits);static unsigned int cb_pcidda_read_eeprom(comedi_device *dev, unsigned int address);static void cb_pcidda_calibrate(comedi_device *dev, unsigned int channel, unsigned int range);/* * 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 comedi_driver driver_cb_pcidda={	driver_name:	"cb_pcidda",	module:		THIS_MODULE,	attach:		cb_pcidda_attach,	detach:		cb_pcidda_detach,};/* * Attach is called by the Comedi core to configure the driver * for a particular board. */static int cb_pcidda_attach(comedi_device *dev, comedi_devconfig *it){	comedi_subdevice *s;	struct pci_dev* pcidev;	int index;	unsigned int dac, digitalio;	printk("comedi%d: cb_pcidda: ",dev->minor);/* * Allocate the private structure area. */	if(alloc_private(dev,sizeof(cb_pcidda_private))<0)		return -ENOMEM;/* * Probe the device to determine what device in the series it is. */	printk("\n");	pci_for_each_dev(pcidev){		if(pcidev->vendor==PCI_VENDOR_ID_CB){			if(it->options[0] || it->options[1]){				if(pcidev->bus->number==it->options[0] &&				   PCI_SLOT(pcidev->devfn)==it->options[1]){					break;				}			}else{				break;			}		}	}	if(!pcidev){		printk("Not a ComputerBoards/MeasurementComputing card on requested position\n");		return -EIO;	}	for(index=0;index<N_BOARDS;index++){		if(cb_pcidda_boards[index].device_id == pcidev->device){			goto found;		}	}	printk("Not a supported ComputerBoards/MeasurementComputing card on "		"requested position\n");				return -EIO;found:	devpriv->pci_dev = pcidev;	dev->board_ptr = cb_pcidda_boards+index;	// "thisboard" macro can be used from here.	printk("Found %s at requested position\n",thisboard->name);	/*	 * Initialize devpriv->control_status and devpriv->adc_fifo to point to	 * their base address.	 */	if(pci_enable_device(devpriv->pci_dev))		return -EIO;	digitalio = pci_resource_start(devpriv->pci_dev, DIGITALIO_BADRINDEX); 	dac = pci_resource_start(devpriv->pci_dev, DAC_BADRINDEX); /* * Allocate the I/O ports. */	if (check_region(digitalio, DIGITALIO_SIZE) < 0)	{		printk("I/O port conflict: failed to allocate ports 0x%x to 0x%x\n",			digitalio, digitalio + DIGITALIO_SIZE - 1);		return -EIO;	}	if (check_region(dac, 8 + thisboard->ao_chans*2) < 0)	{		printk("I/O port conflict: failed to allocate ports 0x%x to 0x%x\n",			dac, dac + 7 + thisboard->ao_chans*2);		return -EIO;	}	request_region(digitalio, DIGITALIO_SIZE, thisboard->name);	devpriv->digitalio = digitalio;	request_region(dac, 8 + thisboard->ao_chans*2,		thisboard->name);	devpriv->dac = dac;/* * Warn about the status of the driver. */	if (thisboard->status == 2)		printk("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. "			"WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. "			"PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n");/* * Initialize dev->board_name. */	dev->board_name = thisboard->name;/* * Allocate the subdevice structures. */	if(alloc_subdevices( dev, 3 ) < 0)		return -ENOMEM;	s = dev->subdevices + 0;	/* analog output subdevice */	s->type = COMEDI_SUBD_AO;	s->subdev_flags = SDF_WRITABLE;	s->n_chan = thisboard->ao_chans;	s->maxdata = (1 << thisboard->ao_bits) - 1;	s->range_table = thisboard->ranges;	s->insn_write = cb_pcidda_ao_winsn;//	s->do_cmd = cb_pcidda_ai_cmd;	s->do_cmdtest = cb_pcidda_ai_cmdtest;	// two 8255 digital io subdevices	s = dev->subdevices + 1;	subdev_8255_init(dev, s, NULL, (unsigned long)(devpriv->digitalio));	s = dev->subdevices + 2;	subdev_8255_init(dev, s, NULL,		(unsigned long)(devpriv->digitalio + PORT2A));	printk(" eeprom:");	for(index = 0; index < EEPROM_SIZE; index++)	{		devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);		printk(" %i:0x%x ", index, devpriv->eeprom_data[index]);	}	printk("\n");	// set calibrations dacs	for(index = 0; index < thisboard->ao_chans; index++)		cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]);	return 1;}/* * _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_pcidda_detach(comedi_device *dev){/* * Deallocate the I/O ports. */	if(devpriv)	{		if(devpriv->digitalio)			release_region(devpriv->digitalio, DIGITALIO_SIZE);		if(devpriv->dac)			release_region(devpriv->dac, 8 + thisboard->ao_chans*2);	}	// cleanup 8255	if(dev->subdevices)	{		subdev_8255_cleanup(dev, dev->subdevices + 1);		subdev_8255_cleanup(dev, dev->subdevices + 2);	}	printk("comedi%d: cb_pcidda: remove\n",dev->minor);	return 0;

⌨️ 快捷键说明

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