📄 ni_at_ao.c
字号:
/* comedi/drivers/ni_at_ao.c Driver for NI AT-AO-6/10 boards COMEDI - Linux Control and Measurement Device Interface Copyright (C) 2000,2002 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: ni_at_ao.oDescription: National Instruments AT-AO-6/10Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10)Status: untestedAuthor: dsUpdated: Fri, 7 Jun 2002 13:20:30 -0700This driver has not been tested, but should work.*//* * Register-level programming information can be found in NI * document 320379.pdf. */#include <linux/comedidev.h>#include <linux/ioport.h>/* board egisters *//* registers with _2_ are accessed when GRP2WR is set in CFG1 */#define ATAO_SIZE 0x20#define ATAO_2_DMATCCLR 0x00 /* W 16 */#define ATAO_DIN 0x00 /* R 16 */#define ATAO_DOUT 0x00 /* W 16 */#define ATAO_CFG2 0x02 /* W 16 */ #define CALLD1 0x8000 #define CALLD0 0x4000 #define FFRTEN 0x2000 #define DAC2S8 0x1000 #define DAC2S6 0x0800 #define DAC2S4 0x0400 #define DAC2S2 0x0200 #define DAC2S0 0x0100 #define LDAC8 0x0080 #define LDAC6 0x0040 #define LDAC4 0x0020 #define LDAC2 0x0010 #define LDAC0 0x0008 #define PROMEN 0x0004 #define SCLK 0x0002 #define SDATA 0x0001#define ATAO_2_INT1CLR 0x02 /* W 16 */#define ATAO_CFG3 0x04 /* W 16 */ #define DMAMODE 0x0040 #define CLKOUT 0x0020 #define RCLKEN 0x0010 #define DOUTEN2 0x0008 #define DOUTEN1 0x0004 #define EN2_5V 0x0002 #define SCANEN 0x0001#define ATAO_2_INT2CLR 0x04 /* W 16 */#define ATAO_82C53_BASE 0x06 /* RW 8 */#define ATAO_82C53_CNTR1 0x06 /* RW 8 */#define ATAO_82C53_CNTR2 0x07 /* RW 8 */#define ATAO_82C53_CNTR3 0x08 /* RW 8 */#define ATAO_82C53_CNTRCMD 0x09 /* W 8 */ #define CNTRSEL1 0x80 #define CNTRSEL0 0x40 #define RWSEL1 0x20 #define RWSEL0 0x10 #define MODESEL2 0x08 #define MODESEL1 0x04 #define MODESEL0 0x02 #define BCDSEL 0x01 /* read-back command */ #define COUNT 0x20 #define STATUS 0x10 #define CNTR3 0x08 #define CNTR2 0x04 #define CNTR1 0x02 /* status */ #define OUT 0x80 #define _NULL 0x40 #define RW1 0x20 #define RW0 0x10 #define MODE2 0x08 #define MODE1 0x04 #define MODE0 0x02 #define BCD 0x01#define ATAO_2_RTSISHFT 0x06 /* W 8 */ #define RSI 0x01#define ATAO_2_RTSISTRB 0x07 /* W 8 */#define ATAO_CFG1 0x0a /* W 16 */ #define EXTINT2EN 0x8000 #define EXTINT1EN 0x4000 #define CNTINT2EN 0x2000 #define CNTINT1EN 0x1000 #define TCINTEN 0x0800 #define CNT1SRC 0x0400 #define CNT2SRC 0x0200 #define FIFOEN 0x0100 #define GRP2WR 0x0080 #define EXTUPDEN 0x0040 #define DMARQ 0x0020 #define DMAEN 0x0010 #define CH_mask 0x000f#define ATAO_STATUS 0x0a /* R 16 */ #define FH 0x0040 #define FE 0x0020 #define FF 0x0010 #define INT2 0x0008 #define INT1 0x0004 #define TCINT 0x0002 #define PROMOUT 0x0001#define ATAO_FIFO_WRITE 0x0c /* W 16 */#define ATAO_FIFO_CLEAR 0x0c /* R 16 */#define ATAO_DACn(x) (0x0c + 2*(x)) /* W *//* * 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 atao_board_struct{ char *name; int n_ao_chans;}atao_board;static atao_board atao_boards[] = { { name: "ai-ao-6", n_ao_chans: 6, }, { name: "ai-ao-10", n_ao_chans: 10, },};#define thisboard ((atao_board *)dev->board_ptr)typedef struct{ unsigned short cfg1; unsigned short cfg2; unsigned short cfg3; /* Used for AO readback */ lsampl_t ao_readback[10];}atao_private;#define devpriv ((atao_private *)dev->private)static int atao_attach(comedi_device *dev,comedi_devconfig *it);static int atao_detach(comedi_device *dev);static comedi_driver driver_atao={ driver_name: "ni_at_ao", module: THIS_MODULE, attach: atao_attach, detach: atao_detach, board_name: atao_boards, offset: sizeof(atao_board), num_names: sizeof(atao_boards) / sizeof(atao_board),};COMEDI_INITCLEANUP(driver_atao);static void atao_reset(comedi_device *dev);static int atao_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int atao_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int atao_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int atao_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int atao_calib_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int atao_calib_insn_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int atao_attach(comedi_device *dev,comedi_devconfig *it){ comedi_subdevice *s; unsigned long iobase; iobase = it->options[0]; if(iobase==0)iobase = 0x1c0; printk("comedi%d: ni_at_ao: 0x%04lx",dev->minor,iobase); if(check_region(iobase, ATAO_SIZE) < 0){ printk(" I/O port conflict\n"); return -EIO; } request_region(iobase, ATAO_SIZE, "ni_at_ao"); dev->iobase = iobase; //dev->board_ptr = atao_probe(dev); dev->board_name = thisboard->name; if(alloc_private(dev,sizeof(atao_private))<0) return -ENOMEM; if(alloc_subdevices(dev, 4)<0) return -ENOMEM; s=dev->subdevices+0; /* analog output subdevice */ s->type=COMEDI_SUBD_AO; s->subdev_flags=SDF_WRITABLE; s->n_chan=thisboard->n_ao_chans; s->maxdata=(1<<12)-1; s->range_table=&range_bipolar10; s->insn_write = &atao_ao_winsn; s->insn_read = &atao_ao_rinsn; s=dev->subdevices+1; /* digital i/o subdevice */ s->type=COMEDI_SUBD_DIO; s->subdev_flags=SDF_READABLE|SDF_WRITABLE; s->n_chan=8; s->maxdata=1; s->range_table=&range_digital; s->insn_bits = atao_dio_insn_bits; s->insn_config = atao_dio_insn_config; s=dev->subdevices+2; /* caldac subdevice */ s->type=COMEDI_SUBD_CALIB; s->subdev_flags = SDF_WRITABLE|SDF_INTERNAL; s->n_chan = 21; s->maxdata = 0xff; s->insn_read = atao_calib_insn_read; s->insn_write = atao_calib_insn_write; s=dev->subdevices+3; /* eeprom subdevice */ //s->type=COMEDI_SUBD_EEPROM; s->type=COMEDI_SUBD_UNUSED; atao_reset(dev); printk("\n"); return 0;}static int atao_detach(comedi_device *dev){ printk("comedi%d: atao: remove\n",dev->minor); if(dev->iobase) release_region(dev->iobase, ATAO_SIZE); return 0;}static void atao_reset(comedi_device *dev){ /* This is the reset sequence described in the manual */ devpriv->cfg1 = 0; outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); outb(RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); outb(0x03, dev->iobase + ATAO_82C53_CNTR1); outb(CNTRSEL0 | RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); devpriv->cfg2 = 0; outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); devpriv->cfg3 = 0; outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); inw(dev->iobase + ATAO_FIFO_CLEAR); devpriv->cfg1 = GRP2WR; outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); outw(0, dev->iobase + ATAO_2_INT1CLR); outw(0, dev->iobase + ATAO_2_INT2CLR); outw(0, dev->iobase + ATAO_2_DMATCCLR); devpriv->cfg1 = 0; outw(devpriv->cfg1, dev->iobase + ATAO_CFG1);}static int atao_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan = CR_CHAN(insn->chanspec); for(i=0;i<insn->n;i++){ outw(data[i], dev->iobase + ATAO_DACn(chan)); devpriv->ao_readback[chan] = data[i]; } return i;}static int atao_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan = CR_CHAN(insn->chanspec); for(i=0;i<insn->n;i++) data[i] = devpriv->ao_readback[chan]; return i;}static int atao_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; if(data[0]){ s->state &= ~data[0]; s->state |= data[0]&data[1]; outw(s->state,dev->iobase + ATAO_DOUT); } data[1]=inw(dev->iobase + ATAO_DIN); return 2;}static int atao_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int chan=CR_CHAN(insn->chanspec); unsigned int mask, bit; if(insn->n!=1)return -EINVAL; /* The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the * value COMEDI_INPUT or COMEDI_OUTPUT. */ mask = (chan < 4) ? 0x0f : 0xf0; bit = (chan < 4) ? DOUTEN1 : DOUTEN2; if(data[0]==COMEDI_OUTPUT){ s->io_bits |= mask; devpriv->cfg3 |= bit; }else{ s->io_bits &= ~mask; devpriv->cfg3 &= ~bit; } outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); return 1;}/* * Figure 2-1 in the manual shows 3 chips labeled DAC8800, which * are 8-channel 8-bit DACs. These are most likely the calibration * DACs. It is not explicitly stated in the manual how to access * the caldacs, but we can guess. */static int atao_calib_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int i; for(i=0;i<insn->n;i++){ data[i]=0; /* XXX */ } return insn->n;}static int atao_calib_insn_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ unsigned int bitstring, bit; unsigned int chan = CR_CHAN(insn->chanspec); bitstring = ((chan&0x7)<<8)|(data[insn->n-1]&0xff); for(bit=1<<(11-1);bit;bit>>=1){ outw(devpriv->cfg2 | ((bit&bitstring)?SDATA:0), dev->iobase + ATAO_CFG2); outw(devpriv->cfg2 | SCLK | ((bit&bitstring)?SDATA:0), dev->iobase + ATAO_CFG2); } /* strobe the appropriate caldac */ outw(devpriv->cfg2 | (((chan>>3) + 1)<<14), dev->iobase + ATAO_CFG2); outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); return insn->n;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -