Added support for 6509, and other boards in family. Will test
authorFrank Mori Hess <fmhess@speakeasy.net>
Mon, 16 Oct 2006 21:01:20 +0000 (21:01 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Mon, 16 Oct 2006 21:01:20 +0000 (21:01 +0000)
tommorrow.

comedi/drivers/ni_65xx.c

index 7c0d3e889238900dc1c2eae4360432eca63dc9de..58a5d7ac29be818e77ce5a4abd522ca7a149e233 100644 (file)
@@ -2,6 +2,9 @@
     comedi/drivers/ni_6514.c
     driver for National Instruments PCI-6514
 
+    Copyright (C) 2006 Jon Grierson <jd@renko.co.uk>
+    Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net>
+
     COMEDI - Linux Control and Measurement Device Interface
     Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org>
 
 /*
 Driver: ni_65xx.o
 Description: National Instruments 65xx static dio boards
-Author: Jon Grierson <jd@renko.co.uk>
+Author: Jon Grierson <jd@renko.co.uk>, Frank Mori Hess <fmhess@users.sourceforge.net>
 Status: testing
 Devices: [National Instruments] PCI-6514 (ni_65xx), PXI-6514, PXI-6509
 Updated: Mon, 17 Jul 2006 16:40:10 +0100
 
 Based on the PCI-6527 driver by ds.
-Should be easily modified for 6509, 651x, 6520, 6521 and 6528
+Should be easily modified for 6509, 651x, 6520, 6521 and 6528 if you
+send in the pci device id of your board.
 
 */
 
@@ -40,9 +44,9 @@ Should be easily modified for 6509, 651x, 6520, 6521 and 6528
 
  */
 
+#define _GNU_SOURCE
 #define DEBUG 1
 #define DEBUG_FLAGS
-
 #include <linux/comedidev.h>
 
 #include "mite.h"
@@ -51,8 +55,30 @@ Should be easily modified for 6509, 651x, 6520, 6521 and 6528
 #define NI6514_DIO_SIZE 4096
 #define NI6514_MITE_SIZE 4096
 
+#define NI_65XX_MAX_NUM_PORTS 12
+static const unsigned ni_65xx_channels_per_port = 8;
+static const unsigned ni_65xx_port_offset = 0x10;
 
-#define Port_Register(x)                       (0x40+(x))
+static inline unsigned Port_Data(unsigned port)
+{
+       return 0x40 + port * ni_65xx_port_offset;
+}
+static inline unsigned Port_Select(unsigned port)
+{
+       return 0x41 + port * ni_65xx_port_offset;
+}
+static inline unsigned Rising_Edge_Detection_Enable(unsigned port)
+{
+       return 0x42 + port * ni_65xx_port_offset;
+}
+static inline unsigned Falling_Edge_Detection_Enable(unsigned port)
+{
+       return 0x43 + port * ni_65xx_port_offset;
+}
+static inline unsigned Filter_Enable(unsigned port)
+{
+       return 0x44 + port * ni_65xx_port_offset;
+}
 #define ID_Register                            0x00
 
 #define Clear_Register                         0x01
@@ -60,7 +86,6 @@ Should be easily modified for 6509, 651x, 6520, 6521 and 6528
 #define ClrOverflow                    0x04
 
 #define Filter_Interval                        0x08
-#define Filter_Enable(x)                       (0x44+(x))
 
 #define Change_Status                          0x02
 #define MasterInterruptStatus          0x04
@@ -74,146 +99,310 @@ Should be easily modified for 6509, 651x, 6520, 6521 and 6528
 #define OverflowIntEnable              0x02
 #define EdgeIntEnable                  0x01
 
-#define Rising_Edge_Detection_Enable(x)                (0x42+(x))
-#define Falling_Edge_Detection_Enable(x)       (0x43+(x))
-
-
-
-static int ni6514_attach(comedi_device *dev,comedi_devconfig *it);
-static int ni6514_detach(comedi_device *dev);
-static comedi_driver driver_ni6514={
+static int ni_65xx_attach(comedi_device *dev,comedi_devconfig *it);
+static int ni_65xx_detach(comedi_device *dev);
+static comedi_driver driver_ni_65xx={
        driver_name:    "ni_65xx",
        module:         THIS_MODULE,
-       attach:         ni6514_attach,
-       detach:         ni6514_detach,
+       attach:         ni_65xx_attach,
+       detach:         ni_65xx_detach,
 };
-COMEDI_INITCLEANUP(driver_ni6514);
+COMEDI_INITCLEANUP(driver_ni_65xx);
 
 typedef struct{
        int dev_id;
-       char *name;
-}ni6514_board;
-static ni6514_board ni6514_boards[] = {
+       const char *name;
+       unsigned num_dio_ports;
+       unsigned num_di_ports;
+       unsigned num_do_ports;
+       unsigned invert_outputs : 1;
+}ni_65xx_board;
+static ni_65xx_board ni_65xx_boards[] = {
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6509",
+               num_dio_ports: 12
+       },
        {
                dev_id:         0x1710,
                name:           "pxi-6509",
+               num_dio_ports: 12
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6510",
+               num_di_ports: 4
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6511",
+               num_di_ports: 8
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pxi-6511",
+               num_di_ports: 8
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6512",
+               num_do_ports: 8
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pxi-6512",
+               num_do_ports: 8
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6513",
+               num_do_ports: 8
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pxi-6513",
+               num_do_ports: 8
        },
        {
                dev_id:         0x7088,
                name:           "pci-6514",
+               num_di_ports: 4,
+               num_do_ports: 4,
+               invert_outputs: 1
        },
        {
                dev_id:         0x70CD,
                name:           "pxi-6514",
+               num_di_ports: 4,
+               num_do_ports: 4,
+               invert_outputs: 1
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6515",
+               num_di_ports: 4,
+               num_do_ports: 4,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pxi-6515",
+               num_di_ports: 4,
+               num_do_ports: 4,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6516",
+               num_do_ports: 4,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6517",
+               num_do_ports: 4,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6518",
+               num_di_ports: 2,
+               num_do_ports: 2,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6519",
+               num_di_ports: 2,
+               num_do_ports: 2,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6520",
+               num_di_ports: 1,
+               num_do_ports: 1,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6521",
+               num_di_ports: 1,
+               num_do_ports: 1,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pxi-6521",
+               num_di_ports: 1,
+               num_do_ports: 1,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pci-6528",
+               num_di_ports: 3,
+               num_do_ports: 3,
+       },
+       {
+               dev_id:         0x0,    //XXX
+               name:           "pxi-6528",
+               num_di_ports: 3,
+               num_do_ports: 3,
        },
 };
 
-#define n_ni6514_boards (sizeof(ni6514_boards)/sizeof(ni6514_boards[0]))
-#define this_board ((ni6514_board *)dev->board_ptr)
+#define n_ni_65xx_boards (sizeof(ni_65xx_boards)/sizeof(ni_65xx_boards[0]))
+static inline const ni_65xx_board* board(comedi_device *dev)
+{
+       return dev->board_ptr;
+}
+static inline unsigned ni_65xx_port_by_channel(unsigned channel)
+{
+       return channel / ni_65xx_channels_per_port;
+}
+static inline unsigned ni_65xx_total_num_ports(const ni_65xx_board *board)
+{
+       return board->num_dio_ports + board->num_di_ports + board->num_do_ports;
+}
 
-static struct pci_device_id ni6514_pci_table[] __devinitdata = {
+static struct pci_device_id ni_65xx_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_NATINST, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_NATINST, 0x7088, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_NATINST, 0x70CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0 }
 };
-MODULE_DEVICE_TABLE(pci, ni6514_pci_table);
+MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table);
 
 typedef struct{
        struct mite_struct *mite;
        unsigned int filter_interval;
-       unsigned int filter_enable;
-}ni6514_private;
-#define devpriv ((ni6514_private *)dev->private)
-
-static int ni6514_find_device(comedi_device *dev,int bus,int slot);
-
-
-static int ni6514_di_insn_config(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+       unsigned short filter_enable[NI_65XX_MAX_NUM_PORTS];
+       unsigned short output_bits[NI_65XX_MAX_NUM_PORTS];
+       unsigned short dio_direction[NI_65XX_MAX_NUM_PORTS];
+}ni_65xx_private;
+static inline ni_65xx_private* private(comedi_device *dev)
 {
-       int chan = CR_CHAN(insn->chanspec);
-       unsigned int interval;
-
-       if(insn->n!=2)return -EINVAL;
+       return dev->private;
+}
 
-       if(data[0] != INSN_CONFIG_FILTER)return -EINVAL;
+typedef struct
+{
+       unsigned base_port;
+}ni_65xx_subdevice_private;
+static inline ni_65xx_subdevice_private* sprivate(comedi_subdevice *subdev)
+{
+       return subdev->private;
+}
+static ni_65xx_subdevice_private* ni_65xx_alloc_subdevice_private(void)
+{
+       ni_65xx_subdevice_private *subdev_private = kmalloc(sizeof(ni_65xx_subdevice_private), GFP_KERNEL);
+       if(subdev_private == NULL) return NULL;
+       memset(subdev_private, 0, sizeof(ni_65xx_subdevice_private));
+       return subdev_private;
+}
 
-       if(data[1]){
-               interval = (data[1]+100)/200;
-               data[1] = interval*200;
+static int ni_65xx_find_device(comedi_device *dev,int bus,int slot);
 
-               if(interval!=devpriv->filter_interval){
-                       writeb(interval&0x000fffff, devpriv->mite->daq_io_addr + Filter_Interval);  /* FIXME 32 bit reg - mask possibly wrong??? */
+static int ni_65xx_config_filter(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       const unsigned chan = CR_CHAN(insn->chanspec);
+       const unsigned port = sprivate(s)->base_port + ni_65xx_port_by_channel(chan);
 
-                       devpriv->filter_interval = interval;
+       if(insn->n != 2)return -EINVAL;
+       if(data[0] != INSN_CONFIG_FILTER) return -EINVAL;
+       if(data[1])
+       {
+               static const unsigned filter_resolution_ns = 200;
+               static const unsigned max_filter_interval = 0xfffff;
+               unsigned interval = (data[1] + (filter_resolution_ns / 2)) / filter_resolution_ns;
+               if(interval > max_filter_interval) interval = max_filter_interval;
+               data[1] = interval * filter_resolution_ns;
+
+               if(interval != private(dev)->filter_interval)
+               {
+                       writeb(interval, private(dev)->mite->daq_io_addr + Filter_Interval);
+                       private(dev)->filter_interval = interval;
                }
 
-               devpriv->filter_enable |= 1<<chan;
+               private(dev)->filter_enable[port] |= 1 << (chan % ni_65xx_channels_per_port);
        }else{
-               devpriv->filter_enable &= ~(1<<chan);
+               private(dev)->filter_enable[port] &= ~(1 << (chan % ni_65xx_channels_per_port));
        }
 
-       writeb(devpriv->filter_enable, devpriv->mite->daq_io_addr + Filter_Enable(0));
-       writeb(devpriv->filter_enable>>8, devpriv->mite->daq_io_addr + Filter_Enable(0x10));
-       writeb(devpriv->filter_enable>>16, devpriv->mite->daq_io_addr + Filter_Enable(0x20));
-       writeb(devpriv->filter_enable>>24, devpriv->mite->daq_io_addr + Filter_Enable(0x30));
+       writeb(private(dev)->filter_enable[port], private(dev)->mite->daq_io_addr + Filter_Enable(port));
 
        return 2;
 }
 
-static int ni6514_di_insn_bits(comedi_device *dev,comedi_subdevice *s,
+static int ni_65xx_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data)
 {
-       if(insn->n!=2)return -EINVAL;
-
-       data[1] = readb(devpriv->mite->daq_io_addr+Port_Register(0));
-       data[1] |= readb(devpriv->mite->daq_io_addr+Port_Register(0x10))<<8;
-       data[1] |= readb(devpriv->mite->daq_io_addr+Port_Register(0x20))<<16;
-       data[1] |= readb(devpriv->mite->daq_io_addr+Port_Register(0x30))<<24;
-
-       return 2;
+       if(insn->n < 1) return -EINVAL;
+       unsigned port = sprivate(s)->base_port + ni_65xx_port_by_channel(CR_CHAN(insn->chanspec));
+       switch(data[0])
+       {
+       case INSN_CONFIG_FILTER:
+               return ni_65xx_config_filter(dev, s, insn, data);
+               break;
+       case INSN_CONFIG_DIO_OUTPUT:
+               if(s->type != COMEDI_SUBD_DIO) return -EINVAL;
+               private(dev)->dio_direction[port] = COMEDI_OUTPUT;
+               writeb(1, private(dev)->mite->daq_io_addr + Port_Select(port));
+               return 1;
+               break;
+       case INSN_CONFIG_DIO_INPUT:
+               if(s->type != COMEDI_SUBD_DIO) return -EINVAL;
+               private(dev)->dio_direction[port] = COMEDI_INPUT;
+               writeb(0, private(dev)->mite->daq_io_addr + Port_Select(port));
+               return 1;
+               break;
+       case INSN_CONFIG_DIO_QUERY:
+               if(s->type != COMEDI_SUBD_DIO) return -EINVAL;
+               data[1] = private(dev)->dio_direction[port];
+               return insn->n;
+               break;
+       default:
+               break;
+       }
+       return -EINVAL;
 }
 
-static int ni6514_do_insn_bits(comedi_device *dev,comedi_subdevice *s,
+static int ni_65xx_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]);
-
-               /* The open relay state on the board cooresponds to 1,
-                * but in Comedi, it is represented by 0. */
-               if(data[0]&0x000000ff){
-                       writeb((s->state^0xff),devpriv->mite->daq_io_addr+Port_Register(0x40));
-               }
-               if(data[0]&0x0000ff00){
-                       writeb((s->state>>8)^0xff,devpriv->mite->daq_io_addr+Port_Register(0x50));
-               }
-               if(data[0]&0x00ff0000){
-                       writeb((s->state>>16)^0xff,devpriv->mite->daq_io_addr+Port_Register(0x60));
-               }
-               if(data[0]&0xff000000){
-                       writeb((s->state>>24)^0xff,devpriv->mite->daq_io_addr+Port_Register(0x70));
+       const unsigned elements_per_bitfield = 2;
+       if(insn->n % elements_per_bitfield) return -EINVAL;
+       const unsigned num_bitfields = insn->n / elements_per_bitfield;
+       unsigned i;
+       for(i = 0; i < num_bitfields; ++i)
+       {
+               const unsigned ports_per_bitfield = 4;
+               const unsigned array_offset = i * elements_per_bitfield;
+               data[array_offset + 1] = 0;
+               unsigned j;
+               for(j = 0; j < ports_per_bitfield; ++j)
+               {
+                       const unsigned port = sprivate(s)->base_port + i * ports_per_bitfield + j;
+                       if(port >= ni_65xx_total_num_ports(board(dev))) break;
+                       const unsigned port_mask = (data[array_offset] >> (j * 8)) & 0xff;
+                       if(port_mask)
+                       {
+                               private(dev)->output_bits[port] &= ~port_mask;
+                               private(dev)->output_bits[port] |= (data[array_offset + 1] >> (j * 8)) & port_mask;
+                               unsigned bits = private(dev)->output_bits[port];
+                               if(board(dev)->invert_outputs) bits = ~bits;
+                               writeb(bits, private(dev)->mite->daq_io_addr + Port_Data(port));
+                       }
+                       data[array_offset + 1] |= readb(private(dev)->mite->daq_io_addr + Port_Data(port));
                }
        }
-       data[1] = s->state;
-
-       return 2;
+       return insn->n;
 }
 
-static irqreturn_t ni6514_interrupt(int irq, void *d, struct pt_regs *regs)
+static irqreturn_t ni_65xx_interrupt(int irq, void *d, struct pt_regs *regs)
 {
        comedi_device *dev = d;
        comedi_subdevice *s = dev->subdevices + 2;
        unsigned int status;
 
-       status = readb(devpriv->mite->daq_io_addr + Change_Status);
+       status = readb(private(dev)->mite->daq_io_addr + Change_Status);
        if((status & MasterInterruptStatus) == 0) return IRQ_NONE;
        if((status & EdgeStatus) == 0) return IRQ_NONE;
 
-       writeb(ClrEdge | ClrOverflow, devpriv->mite->daq_io_addr + Clear_Register);
+       writeb(ClrEdge | ClrOverflow, private(dev)->mite->daq_io_addr + Clear_Register);
 
        comedi_buf_put(s->async, 0);
        s->async->events |= COMEDI_CB_EOS;
@@ -221,7 +410,7 @@ static irqreturn_t ni6514_interrupt(int irq, void *d, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static int ni6514_intr_cmdtest(comedi_device *dev,comedi_subdevice *s,
+static int ni_65xx_intr_cmdtest(comedi_device *dev,comedi_subdevice *s,
        comedi_cmd *cmd)
 {
        int err=0;
@@ -288,26 +477,26 @@ static int ni6514_intr_cmdtest(comedi_device *dev,comedi_subdevice *s,
        return 0;
 }
 
-static int ni6514_intr_cmd(comedi_device *dev,comedi_subdevice *s)
+static int ni_65xx_intr_cmd(comedi_device *dev,comedi_subdevice *s)
 {
        //comedi_cmd *cmd = &s->async->cmd;
 
-       writeb(ClrEdge|ClrOverflow, devpriv->mite->daq_io_addr + Clear_Register);
+       writeb(ClrEdge|ClrOverflow, private(dev)->mite->daq_io_addr + Clear_Register);
        writeb(FallingEdgeIntEnable|RisingEdgeIntEnable|
                MasterInterruptEnable|EdgeIntEnable,
-               devpriv->mite->daq_io_addr + Master_Interrupt_Control);
+               private(dev)->mite->daq_io_addr + Master_Interrupt_Control);
 
        return 0;
 }
 
-static int ni6514_intr_cancel(comedi_device *dev,comedi_subdevice *s)
+static int ni_65xx_intr_cancel(comedi_device *dev,comedi_subdevice *s)
 {
-       writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
+       writeb(0x00, private(dev)->mite->daq_io_addr + Master_Interrupt_Control);
 
        return 0;
 }
 
-static int ni6514_intr_insn_bits(comedi_device *dev, comedi_subdevice *s,
+static int ni_65xx_intr_insn_bits(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn, lsampl_t *data)
 {
        if(insn->n < 1)return -EINVAL;
@@ -316,103 +505,135 @@ static int ni6514_intr_insn_bits(comedi_device *dev, comedi_subdevice *s,
        return 2;
 }
 
-static int ni6514_intr_insn_config(comedi_device *dev, comedi_subdevice *s,
+static int ni_65xx_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], devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0));
-       writeb(data[1]>>8, devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x10));
-       writeb(data[1]>>16, devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x20));
-       writeb(data[1]>>24, devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x30));
+       writeb(data[1], private(dev)->mite->daq_io_addr + Rising_Edge_Detection_Enable(0));
+       writeb(data[1]>>8, private(dev)->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x10));
+       writeb(data[1]>>16, private(dev)->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x20));
+       writeb(data[1]>>24, private(dev)->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x30));
 
-       writeb(data[2], devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0));
-       writeb(data[2]>>8, devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x10));
-       writeb(data[2]>>16, devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x20));
-       writeb(data[2]>>24, devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x30));
+       writeb(data[2], private(dev)->mite->daq_io_addr + Falling_Edge_Detection_Enable(0));
+       writeb(data[2]>>8, private(dev)->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x10));
+       writeb(data[2]>>16, private(dev)->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x20));
+       writeb(data[2]>>24, private(dev)->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x30));
 
        return 2;
 }
 
 
-static int ni6514_attach(comedi_device *dev,comedi_devconfig *it)
+static int ni_65xx_attach(comedi_device *dev,comedi_devconfig *it)
 {
        comedi_subdevice *s;
        int ret;
 
-       printk("comedi%d: ni6514:",dev->minor);
+       printk("comedi%d: ni_65xx:",dev->minor);
 
-       if((ret=alloc_private(dev,sizeof(ni6514_private)))<0)
+       if((ret=alloc_private(dev,sizeof(ni_65xx_private)))<0)
                return ret;
 
-       ret=ni6514_find_device(dev,it->options[0],it->options[1]);
+       ret=ni_65xx_find_device(dev,it->options[0],it->options[1]);
        if(ret<0)return ret;
 
-       ret = mite_setup(devpriv->mite);
+       ret = mite_setup(private(dev)->mite);
        if(ret < 0)
        {
                printk("error setting up mite\n");
                return ret;
        }
 
-       dev->board_name=this_board->name;
-       dev->irq=mite_irq(devpriv->mite);
+       dev->board_name = board(dev)->name;
+       dev->irq = mite_irq(private(dev)->mite);
        printk(" %s",dev->board_name);
 
-       printk(" ID=0x%02x", readb(devpriv->mite->daq_io_addr + ID_Register));
+       printk(" ID=0x%02x", readb(private(dev)->mite->daq_io_addr + ID_Register));
 
-       if((ret=alloc_subdevices(dev,3))<0)
+       if((ret=alloc_subdevices(dev, 4)) < 0)
                return ret;
 
-       s=dev->subdevices+0;
-       s->type=COMEDI_SUBD_DI;
-       s->subdev_flags=SDF_READABLE;
-       s->n_chan=32;
-       s->range_table=&range_digital;
-       s->maxdata=1;
-       s->insn_config = ni6514_di_insn_config;
-       s->insn_bits = ni6514_di_insn_bits;
-
-       s=dev->subdevices+1;
-       s->type=COMEDI_SUBD_DO;
-       s->subdev_flags=SDF_READABLE|SDF_WRITABLE;
-       s->n_chan=32;
-       s->range_table=&range_digital;
-       s->maxdata=1;
-       s->insn_bits = ni6514_do_insn_bits;
+       s = dev->subdevices + 0;
+       if(board(dev)->num_di_ports)
+       {
+               s->type = COMEDI_SUBD_DI;
+               s->subdev_flags = SDF_READABLE;
+               s->n_chan = board(dev)->num_di_ports * ni_65xx_channels_per_port;
+               s->range_table = &range_digital;
+               s->maxdata = 1;
+               s->insn_config = ni_65xx_dio_insn_config;
+               s->insn_bits = ni_65xx_dio_insn_bits;
+               s->private = ni_65xx_alloc_subdevice_private();
+               if(s->private == NULL) return -ENOMEM;
+               sprivate(s)->base_port = 0;
+       }else
+       {
+               s->type = COMEDI_SUBD_UNUSED;
+       }
+
+       s=dev->subdevices + 1;
+       if(board(dev)->num_do_ports)
+       {
+               s->type = COMEDI_SUBD_DO;
+               s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+               s->n_chan = board(dev)->num_di_ports * ni_65xx_channels_per_port;
+               s->range_table = &range_digital;
+               s->maxdata = 1;
+               s->insn_bits = ni_65xx_dio_insn_bits;
+               s->private = ni_65xx_alloc_subdevice_private();
+               if(s->private == NULL) return -ENOMEM;
+               sprivate(s)->base_port = board(dev)->num_di_ports;
+       }else
+       {
+               s->type = COMEDI_SUBD_UNUSED;
+       }
 
        s=dev->subdevices + 2;
+       if(board(dev)->num_dio_ports)
+       {
+               s->type = COMEDI_SUBD_DIO;
+               s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+               s->n_chan = board(dev)->num_dio_ports * ni_65xx_channels_per_port;
+               s->range_table=&range_digital;
+               s->maxdata=1;
+               s->insn_config = ni_65xx_dio_insn_config;
+               s->insn_bits = ni_65xx_dio_insn_bits;
+               s->private = ni_65xx_alloc_subdevice_private();
+               if(s->private == NULL) return -ENOMEM;
+               sprivate(s)->base_port = 0;
+       }else
+       {
+               s->type = COMEDI_SUBD_UNUSED;
+       }
+
+       s=dev->subdevices + 3;
        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 = ni6514_intr_cmdtest;
-       s->do_cmd = ni6514_intr_cmd;
-       s->cancel = ni6514_intr_cancel;
-       s->insn_bits = ni6514_intr_insn_bits;
-       s->insn_config = ni6514_intr_insn_config;
-
-       writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0));
-       writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0x10));
-       writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0x20));
-       writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0x30));
-
-       writeb(0x00,devpriv->mite->daq_io_addr+Port_Register(0x40));
-       writeb(0x00,devpriv->mite->daq_io_addr+Port_Register(0x50));
-       writeb(0x00,devpriv->mite->daq_io_addr+Port_Register(0x60));
-       writeb(0x00,devpriv->mite->daq_io_addr+Port_Register(0x70));
-
+       s->do_cmdtest = ni_65xx_intr_cmdtest;
+       s->do_cmd = ni_65xx_intr_cmd;
+       s->cancel = ni_65xx_intr_cancel;
+       s->insn_bits = ni_65xx_intr_insn_bits;
+       s->insn_config = ni_65xx_intr_insn_config;
+
+       unsigned i;
+       for(i = 0; i < ni_65xx_total_num_ports(board(dev)); ++i)
+       {
+               writeb(0x00, private(dev)->mite->daq_io_addr + Filter_Enable(i));
+               writeb(0x00,private(dev)->mite->daq_io_addr + Port_Data(i));
+       }
        writeb(ClrEdge|ClrOverflow,
-               devpriv->mite->daq_io_addr + Clear_Register);
-       writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
+               private(dev)->mite->daq_io_addr + Clear_Register);
+       writeb(0x00, private(dev)->mite->daq_io_addr + Master_Interrupt_Control);
 
        /* Set filter interval to 0  (32bit reg) */
-       writeb(0x00000000, devpriv->mite->daq_io_addr + Filter_Interval);
+       writeb(0x00000000, private(dev)->mite->daq_io_addr + Filter_Interval);
 
-       ret=comedi_request_irq(dev->irq,ni6514_interrupt,SA_SHIRQ,"ni6514",dev);
+       ret=comedi_request_irq(dev->irq,ni_65xx_interrupt,SA_SHIRQ,"ni_65xx",dev);
        if(ret<0){
                dev->irq=0;
                printk(" irq not available");
@@ -423,24 +644,35 @@ static int ni6514_attach(comedi_device *dev,comedi_devconfig *it)
        return 0;
 }
 
-static int ni6514_detach(comedi_device *dev)
+static int ni_65xx_detach(comedi_device *dev)
 {
-       if(devpriv && devpriv->mite && devpriv->mite->daq_io_addr){
-               writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
+       if(private(dev) && private(dev)->mite && private(dev)->mite->daq_io_addr){
+               writeb(0x00, private(dev)->mite->daq_io_addr + Master_Interrupt_Control);
        }
 
        if(dev->irq){
                comedi_free_irq(dev->irq,dev);
        }
 
-       if(devpriv && devpriv->mite){
-               mite_unsetup(devpriv->mite);
+       if(private(dev))
+       {
+               unsigned i;
+               for(i = 0; i < dev->n_subdevices; ++i)
+               {
+                       if(dev->subdevices[i].private)
+                       {
+                               kfree(dev->subdevices[i].private);
+                               dev->subdevices[i].private = NULL;
+                       }
+               }
+               if(private(dev)->mite){
+                       mite_unsetup(private(dev)->mite);
+               }
        }
-
        return 0;
 }
 
-static int ni6514_find_device(comedi_device *dev,int bus,int slot)
+static int ni_65xx_find_device(comedi_device *dev,int bus,int slot)
 {
        struct mite_struct *mite;
        int i;
@@ -452,10 +684,10 @@ static int ni6514_find_device(comedi_device *dev,int bus,int slot)
                           slot!=PCI_SLOT(mite->pcidev->devfn))
                                continue;
                }
-               for(i=0;i<n_ni6514_boards;i++){
-                       if(mite_device_id(mite)==ni6514_boards[i].dev_id){
-                               dev->board_ptr = ni6514_boards + i;
-                               devpriv->mite=mite;
+               for(i=0;i<n_ni_65xx_boards;i++){
+                       if(mite_device_id(mite)==ni_65xx_boards[i].dev_id){
+                               dev->board_ptr = ni_65xx_boards + i;
+                               private(dev)->mite=mite;
                                return 0;
                        }
                }