From: David Schleef Date: Fri, 31 Jan 2003 03:48:38 +0000 (+0000) Subject: New driver X-Git-Tag: r0_7_67x~121 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=211b1c17c6a8124daf6f7b54c7d661e9e500ca6f;p=comedi.git New driver --- diff --git a/comedi/Config.in b/comedi/Config.in index 337437cb..75144d2f 100644 --- a/comedi/Config.in +++ b/comedi/Config.in @@ -58,6 +58,7 @@ if [ "$CONFIG_COMEDI_NI" = "y" ];then if [ "$CONFIG_PCI" = "y" ];then dep_tristate ' PCI-MIO E series' CONFIG_COMEDI_NI_PCIMIO $CONFIG_COMEDI dep_tristate ' NI PCI-DIO series' CONFIG_COMEDI_NI_PCIDIO $CONFIG_COMEDI + dep_tristate ' NI 6527 series' CONFIG_COMEDI_NI_6527 $CONFIG_COMEDI dep_tristate ' NI 670x series' CONFIG_COMEDI_NI_670X $CONFIG_COMEDI if [ "$CONFIG_COMEDI_NI_PCIMIO" = "y" -o "$CONFIG_COMEDI_NI_PCIDIO" = "y" -o "$CONFIG_COMEDI_NI_670X" = "y" ];then define_bool CONFIG_COMEDI_MITE y diff --git a/comedi/drivers/Makefile.in b/comedi/drivers/Makefile.in index af08f4ee..9d51e707 100644 --- a/comedi/drivers/Makefile.in +++ b/comedi/drivers/Makefile.in @@ -43,6 +43,7 @@ select(CONFIG_COMEDI_NI_ATMIO ni_atmio.o) select(CONFIG_COMEDI_NI_MIO_CS ni_mio_cs.o) select(CONFIG_COMEDI_NI_PCIMIO ni_pcimio.o) select(CONFIG_COMEDI_NI_PCIDIO ni_pcidio.o) +select(CONFIG_COMEDI_NI_6527 ni_6527.o) select(CONFIG_COMEDI_NI_ATMIO16D ni_atmio16d.o) select(CONFIG_COMEDI_NI_AT_A2150 ni_at_a2150.o) select(CONFIG_COMEDI_NI_LABPC ni_labpc.o) diff --git a/comedi/drivers/ni_6527.c b/comedi/drivers/ni_6527.c new file mode 100644 index 00000000..76649d14 --- /dev/null +++ b/comedi/drivers/ni_6527.c @@ -0,0 +1,451 @@ +/* + comedi/drivers/ni_6527.c + driver for National Instruments PCI-6527 + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1999,2002,2003 David A. Schleef + + 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: ni6527.o +Description: National Instruments 6527 +Author: ds +Status: works +Devices: [National Instruments] 6527 +Updated: Sat, 25 Jan 2003 13:24:40 -0800 + + +*/ + +/* + Manuals (available from ftp://ftp.natinst.com/support/manuals) + + 370106b.pdf 6527 Register Level Programmer Manual + + */ + +#define DEBUG 1 +#define DEBUG_FLAGS + +#include + +#include "mite.h" + + +#define NI6527_DIO_SIZE 4096 +#define NI6527_MITE_SIZE 4096 + + +#define Port_Register(x) (0x00+(x)) +#define ID_Register 0x06 + +#define Clear_Register 0x07 +#define ClrEdge 0x08 +#define ClrOverflow 0x04 +#define ClrFilter 0x02 +#define ClrInterval 0x01 + +#define Filter_Interval(x) (0x08+(x)) +#define Filter_Enable(x) (0x0c+(x)) + +#define Change_Status 0x14 +#define MasterInterruptStatus 0x04 +#define Overflow 0x02 +#define EdgeStatus 0x01 + +#define Master_Interrupt_Control 0x15 +#define FallingEdgeIntEnable 0x10 +#define RisingEdgeIntEnable 0x08 +#define MasterInterruptEnable 0x04 +#define OverflowIntEnable 0x02 +#define EdgeIntEnable 0x01 + +#define Rising_Edge_Detection_Enable(x) (0x018+(x)) +#define Falling_Edge_Detection_Enable(x) (0x020+(x)) + + + +static int ni6527_attach(comedi_device *dev,comedi_devconfig *it); +static int ni6527_detach(comedi_device *dev); +static comedi_driver driver_ni6527={ + driver_name: "ni6527", + module: THIS_MODULE, + attach: ni6527_attach, + detach: ni6527_detach, +}; +COMEDI_INITCLEANUP(driver_ni6527); + +typedef struct{ + int dev_id; + char *name; +}ni6527_board; +static ni6527_board ni6527_boards[] = { + { + dev_id: 0x2b20, + name: "pci-6527", + }, + { + dev_id: 0x2b10, + name: "pxi-6527", + }, +}; + +#define n_ni6527_boards (sizeof(ni6527_boards)/sizeof(ni6527_boards[0])) +#define this_board ((ni6527_board *)dev->board_ptr) + +static struct pci_device_id ni6527_pci_table[] __devinitdata = { + { PCI_VENDOR_ID_NATINST, 0x2b10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NATINST, 0x2b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni6527_pci_table); + +typedef struct{ + struct mite_struct *mite; + unsigned int filter_interval; + unsigned int filter_enable; +}ni6527_private; +#define devpriv ((ni6527_private *)dev->private) + +static int ni6527_find_device(comedi_device *dev,int bus,int slot); + + +static int ni6527_di_insn_config(comedi_device *dev,comedi_subdevice *s, + comedi_insn *insn,lsampl_t *data) +{ + int chan = CR_CHAN(insn->chanspec); + unsigned int interval; + + if(insn->n!=2)return -EINVAL; + + if(data[0] != INSN_CONFIG_FILTER)return -EINVAL; + + if(data[1]){ + interval = (data[1]+100)/200; + data[1] = interval*200; + + if(interval!=devpriv->filter_interval){ + writeb(interval&0xff, dev->iobase + Filter_Interval(0)); + writeb((interval>>8)&0xff, dev->iobase + Filter_Interval(1)); + writeb((interval>>16)&0x0f, dev->iobase + Filter_Interval(1)); + + writeb(ClrInterval, dev->iobase + Clear_Register); + + devpriv->filter_interval = interval; + } + + devpriv->filter_enable |= 1<filter_enable &= ~(1<filter_enable, dev->iobase + Filter_Enable(0)); + writeb(devpriv->filter_enable>>8, dev->iobase + Filter_Enable(1)); + writeb(devpriv->filter_enable>>16, dev->iobase + Filter_Enable(2)); + + return 2; +} + +static int ni6527_di_insn_bits(comedi_device *dev,comedi_subdevice *s, + comedi_insn *insn,lsampl_t *data) +{ + if(insn->n!=2)return -EINVAL; + + data[1] = readb(dev->iobase+Port_Register(0)); + data[1] |= readb(dev->iobase+Port_Register(0))<<8; + data[1] |= readb(dev->iobase+Port_Register(0))<<16; + + return 2; +} + +static int ni6527_do_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]); + + /* The open relay state on the board cooresponds to 1, + * but in Comedi, it is represented by 0. */ + if(data[0]&0x0000ff){ + writeb((s->state^0xff),dev->iobase+Port_Register(3)); + } + if(data[0]&0x00ff00){ + writeb((s->state>>8)^0xff,dev->iobase+Port_Register(4)); + } + if(data[0]&0xff0000){ + writeb((s->state>>16)^0xff,dev->iobase+Port_Register(5)); + } + } + data[1] = s->state; + + return 2; +} + +static void ni6527_interrupt(int irq, void *d, struct pt_regs *regs) +{ + comedi_device *dev = d; + comedi_subdevice *s = dev->subdevices + 2; + unsigned int status; + + status = readb(dev->iobase + Change_Status); + if(!status&MasterInterruptStatus)return; + if(!status&EdgeStatus)return; + + writeb(ClrEdge | ClrOverflow, dev->iobase + Clear_Register); + + comedi_buf_put(s->async, 0); + s->async->events |= COMEDI_CB_EOS; + comedi_event(dev,s,s->async->events); +} + +static int ni6527_intr_cmdtest(comedi_device *dev,comedi_subdevice *s, + comedi_cmd *cmd) +{ + int err=0; + int tmp; + + /* step 1: make sure trigger sources are trivially valid */ + + tmp=cmd->start_src; + cmd->start_src &= TRIG_NOW; + if(!cmd->start_src || tmp!=cmd->start_src)err++; + + tmp=cmd->scan_begin_src; + cmd->scan_begin_src &= TRIG_OTHER; + if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; + + tmp=cmd->convert_src; + cmd->convert_src &= TRIG_FOLLOW; + if(!cmd->convert_src || tmp!=cmd->convert_src)err++; + + tmp=cmd->scan_end_src; + cmd->scan_end_src &= TRIG_COUNT; + if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++; + + tmp=cmd->stop_src; + cmd->stop_src &= TRIG_COUNT; + if(!cmd->stop_src || tmp!=cmd->stop_src)err++; + + if(err)return 1; + + /* step 2: make sure trigger sources are unique and mutually compatible */ + + if(err)return 2; + + /* step 3: make sure arguments are trivially compatible */ + + if(cmd->start_arg!=0){ + cmd->start_arg=0; + err++; + } + if(cmd->scan_begin_arg!=0){ + cmd->scan_begin_arg = 0; + err++; + } + if(cmd->convert_arg!=0){ + cmd->convert_arg = 0; + err++; + } + + if(cmd->scan_end_arg!=1){ + cmd->scan_end_arg=1; + err++; + } + if(cmd->stop_arg!=0){ + cmd->stop_arg=0; + err++; + } + + if(err)return 3; + + /* step 4: fix up any arguments */ + + if(err)return 4; + + return 0; +} + +static int ni6527_intr_cmd(comedi_device *dev,comedi_subdevice *s) +{ + //comedi_cmd *cmd = &s->async->cmd; + + writeb(ClrEdge|ClrOverflow, dev->iobase + Clear_Register); + writeb(FallingEdgeIntEnable|RisingEdgeIntEnable| + MasterInterruptEnable|EdgeIntEnable, + dev->iobase + Master_Interrupt_Control); + + return 0; +} + +static int ni6527_intr_cancel(comedi_device *dev,comedi_subdevice *s) +{ + writeb(0x00, dev->iobase + Master_Interrupt_Control); + + return 0; +} + +static int ni6527_intr_insn_bits(comedi_device *dev, comedi_subdevice *s, + comedi_insn *insn, lsampl_t *data) +{ + if(insn->n < 1)return -EINVAL; + + data[1] = 0; + return 2; +} + +static int ni6527_intr_insn_config(comedi_device *dev, comedi_subdevice *s, + comedi_insn *insn, lsampl_t *data) +{ + if(insn->n < 1)return -EINVAL; + if(data[0] != INSN_CONFIG_CHANGE_NOTIFY)return -EINVAL; + + writeb(data[1], dev->iobase + Rising_Edge_Detection_Enable(0)); + writeb(data[1]>>8, dev->iobase + Rising_Edge_Detection_Enable(1)); + writeb(data[1]>>16, dev->iobase + Rising_Edge_Detection_Enable(2)); + + writeb(data[2], dev->iobase + Falling_Edge_Detection_Enable(0)); + writeb(data[2]>>8, dev->iobase + Falling_Edge_Detection_Enable(1)); + writeb(data[2]>>16, dev->iobase + Falling_Edge_Detection_Enable(2)); + + return 2; +} + + +static int ni6527_attach(comedi_device *dev,comedi_devconfig *it) +{ + comedi_subdevice *s; + int ret; + + printk("comedi%d: ni6527:",dev->minor); + + if((ret=alloc_private(dev,sizeof(ni6527_private)))<0) + return ret; + + ret=ni6527_find_device(dev,it->options[0],it->options[1]); + if(ret<0)return ret; + + ret = mite_setup(devpriv->mite); + if(ret < 0) + { + printk("error setting up mite\n"); + return ret; + } + dev->iobase = mite_iobase(devpriv->mite); + + dev->board_name=this_board->name; + dev->irq=mite_irq(devpriv->mite); + printk(" %s",dev->board_name); + + printk(" ID=0x%02x", readb(dev->iobase + ID_Register)); + + dev->n_subdevices=2; + if((ret=alloc_subdevices(dev))<0) + return ret; + + s=dev->subdevices+0; + s->type=COMEDI_SUBD_DI; + s->subdev_flags=SDF_READABLE; + s->n_chan=24; + s->range_table=&range_digital; + s->maxdata=1; + s->insn_config = ni6527_di_insn_config; + s->insn_bits = ni6527_di_insn_bits; + + s=dev->subdevices+1; + s->type=COMEDI_SUBD_DO; + s->subdev_flags=SDF_READABLE|SDF_WRITABLE; + s->n_chan=24; + s->range_table=&range_unknown; /* FIXME: actually conductance */ + s->maxdata=1; + s->insn_bits = ni6527_do_insn_bits; + + s=dev->subdevices + 2; + dev->read_subdev = s; + s->type=COMEDI_SUBD_DI; + s->subdev_flags=SDF_READABLE; + s->n_chan=1; + s->range_table=&range_unknown; + s->maxdata=1; + s->do_cmdtest = ni6527_intr_cmdtest; + s->do_cmd = ni6527_intr_cmd; + s->cancel = ni6527_intr_cancel; + s->insn_bits = ni6527_intr_insn_bits; + s->insn_config = ni6527_intr_insn_config; + + writeb(0x00, dev->iobase + Filter_Enable(0)); + writeb(0x00, dev->iobase + Filter_Enable(1)); + writeb(0x00, dev->iobase + Filter_Enable(2)); + + writeb(ClrEdge|ClrOverflow|ClrFilter|ClrInterval, + dev->iobase + Clear_Register); + writeb(0x00, dev->iobase + Master_Interrupt_Control); + + ret=comedi_request_irq(dev->irq,ni6527_interrupt,SA_SHIRQ,"ni6527",dev); + if(ret<0){ + dev->irq=0; + printk(" irq not available"); + } + + printk("\n"); + + return 0; +} + +static int ni6527_detach(comedi_device *dev) +{ + if(dev->iobase){ + writeb(0x00, dev->iobase + Master_Interrupt_Control); + } + + if(dev->irq){ + comedi_free_irq(dev->irq,dev); + } + + if(devpriv && devpriv->mite){ + mite_unsetup(devpriv->mite); + } + + return 0; +} + +static int ni6527_find_device(comedi_device *dev,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){ + if(bus!=mite->pcidev->bus->number || + slot!=PCI_SLOT(mite->pcidev->devfn)) + continue; + } + for(i=0;iboard_ptr = ni6527_boards + i; + devpriv->mite=mite; + return 0; + } + } + } + printk("no device found\n"); + mite_list_devices(); + return -EIO; +} +