New driver
authorDavid Schleef <ds@schleef.org>
Fri, 31 Jan 2003 03:48:38 +0000 (03:48 +0000)
committerDavid Schleef <ds@schleef.org>
Fri, 31 Jan 2003 03:48:38 +0000 (03:48 +0000)
comedi/Config.in
comedi/drivers/Makefile.in
comedi/drivers/ni_6527.c [new file with mode: 0644]

index 337437cb75430f5af6eaf67e1474ea07ce300071..75144d2f2fdb009ea4cab658a087e2ce1c5a99d9 100644 (file)
@@ -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
index af08f4ee01180f8509ac0e2140d929990d258908..9d51e7070cc5b9059d1e589c82d46b61fb87dce2 100644 (file)
@@ -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 (file)
index 0000000..76649d1
--- /dev/null
@@ -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 <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: 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 <linux/comedidev.h>
+
+#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<<chan;
+       }else{
+               devpriv->filter_enable &= ~(1<<chan);
+       }
+       
+       writeb(devpriv->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;i<n_ni6527_boards;i++){
+                       if(mite_device_id(mite)==ni6527_boards[i].dev_id){
+                               dev->board_ptr = ni6527_boards + i;
+                               devpriv->mite=mite;
+                               return 0;
+                       }
+               }
+       }
+       printk("no device found\n");
+       mite_list_devices();
+       return -EIO;
+}
+