Realized that "struct ni_gpct" needs to have a "ni_gpct_device"
authorFrank Mori Hess <fmhess@speakeasy.net>
Mon, 9 Jul 2007 20:12:56 +0000 (20:12 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Mon, 9 Jul 2007 20:12:56 +0000 (20:12 +0000)
struct split out of it, which is shared by all counters on a board.

Need to hold mite_channel_lock in ni_mio_common when calling ni_tio
functions that use mite channel.

comedi/drivers/ni_660x.c
comedi/drivers/ni_mio_common.c
comedi/drivers/ni_stc.h
comedi/drivers/ni_tio.c
comedi/drivers/ni_tio.h

index a7e86212d2ddfd422828aa78bde00453bb7a01ab..e85e6d2d003d10669035ef43083f79b52c0d9770 100644 (file)
@@ -124,6 +124,7 @@ typedef enum
        G3DMAConfigRegister,
        G3DMAStatusRegister,
        ClockConfigRegister,
+       DMAConfigRegister,      // XXX will need to use this according to mite channel used
        IOConfigReg0_1,
        IOConfigReg2_3,
        IOConfigReg4_5,
@@ -254,6 +255,7 @@ static const NI_660xRegisterData registerData[NumRegisters] =
        {"G3 DMA Config Register", 0x1BA, NI_660x_WRITE, DATA_2B},
        {"G3 DMA Status Register", 0x1BA, NI_660x_READ, DATA_2B},
        {"Clock Config Register", 0x73C, NI_660x_WRITE, DATA_4B},
+       {"DMA Configuration Register", 0x76c, NI_660x_WRITE, DATA_4B},
        {"IO Config Register 0-1", 0x77C, NI_660x_READ_WRITE, DATA_2B}, // READWRITE
        {"IO Config Register 2-3", 0x77E, NI_660x_READ_WRITE, DATA_2B},
        {"IO Config Register 4-5", 0x780, NI_660x_READ_WRITE, DATA_2B},
@@ -349,7 +351,7 @@ typedef struct
 {
        struct mite_struct *mite;
        int boardtype;
-       struct ni_gpct counters[NI_660X_MAX_NUM_COUNTERS];
+       struct ni_gpct_device *counter_dev;
        uint64_t pfi_direction_bits;
 }ni_660x_private;
 
@@ -572,10 +574,11 @@ static NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
        return ni_660x_register;
 }
 
-static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
+static void ni_gpct_write_register(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
 {
        NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
-       comedi_device *dev = counter->dev;
+       comedi_device *dev = counter_dev->dev;
        void * const write_address = devpriv->mite->daq_io_addr + GPCT_OFFSET[counter->chip_index] + registerData[ni_660x_register].offset;
 
        switch(registerData[ni_660x_register].size)
@@ -593,10 +596,11 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum
        }
 }
 
-static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg)
+static unsigned ni_gpct_read_register(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, enum ni_gpct_register reg)
 {
        NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
-       comedi_device *dev = counter->dev;
+       comedi_device *dev = counter_dev->dev;
        void * const read_address = devpriv->mite->daq_io_addr + GPCT_OFFSET[counter->chip_index] + registerData[ni_660x_register].offset;
 
        switch(registerData[ni_660x_register].size)
@@ -660,6 +664,10 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
        // we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg
        writew(0, devpriv->mite->daq_io_addr + registerData[STCDIOControl].offset);
 
+       devpriv->counter_dev = ni_gpct_device_construct(dev,
+               &ni_gpct_write_register, &ni_gpct_read_register,
+               ni_gpct_variant_660x, thisboard->n_ctrs);
+       if(devpriv->counter_dev == NULL) return -ENOMEM;
        for(i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i)
        {
                s = dev->subdevices + 2 + i;
@@ -672,16 +680,12 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
                        s->insn_read = ni_660x_GPCT_rinsn;
                        s->insn_write = ni_660x_GPCT_winsn;
                        s->insn_config = ni_660x_GPCT_insn_config;
-                       s->private = &devpriv->counters[i];
-
-                       devpriv->counters[i].dev = dev;
-                       devpriv->counters[i].chip_index = i / CTRS_PER_CHIP;
-                       devpriv->counters[i].counter_index = i % CTRS_PER_CHIP;
-                       devpriv->counters[i].write_register = ni_gpct_write_register;
-                       devpriv->counters[i].read_register = ni_gpct_read_register;
-                       devpriv->counters[i].variant = ni_gpct_variant_660x;
-                       devpriv->counters[i].clock_period_ps = 0;
-                       devpriv->counters[i].mite_chan = NULL;
+                       s->private = &devpriv->counter_dev->counters[i];
+
+                       devpriv->counter_dev->counters[i].chip_index = i / CTRS_PER_CHIP;
+                       devpriv->counter_dev->counters[i].counter_index = i % CTRS_PER_CHIP;
+                       devpriv->counter_dev->counters[i].clock_period_ps = 0;
+                       devpriv->counter_dev->counters[i].mite_chan = NULL;
                }else
                {
                        s->type = COMEDI_SUBD_UNUSED;
@@ -693,7 +697,7 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
        }
        for(i = 0; i < thisboard->n_ctrs; ++i)
        {
-               ni_tio_init_counter(&devpriv->counters[i]);
+               ni_tio_init_counter(devpriv->counter_dev, &devpriv->counter_dev->counters[i]);
        }
 
        printk("attached\n");
@@ -706,9 +710,13 @@ ni_660x_detach(comedi_device *dev)
 {
        printk("comedi%d: ni_660x: remove\n",dev->minor);
 
-       if (dev->private && devpriv->mite)
-               mite_unsetup(devpriv->mite);
-
+       if(dev->private)
+       {
+               if(devpriv->counter_dev)
+                       ni_gpct_device_destroy(devpriv->counter_dev);
+               if(devpriv->mite)
+                       mite_unsetup(devpriv->mite);
+       }
        /* Free irq */
 
        if(dev->irq) comedi_free_irq(dev->irq,dev);
@@ -722,7 +730,7 @@ ni_660x_GPCT_rinsn(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn, lsampl_t *data)
 {
        struct ni_gpct *counter = s->private;
-       return ni_tio_rinsn(counter, insn, data);
+       return ni_tio_rinsn(devpriv->counter_dev, counter, insn, data);
 }
 
 static void init_tio_chip(comedi_device *dev, int chipset)
@@ -744,7 +752,7 @@ ni_660x_GPCT_insn_config(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn, lsampl_t *data)
 {
        struct ni_gpct *counter = s->private;
-       return ni_tio_insn_config(counter, insn, data);
+       return ni_tio_insn_config(devpriv->counter_dev, counter, insn, data);
 }
 
 static int ni_660x_GPCT_winsn(comedi_device *dev,
@@ -753,7 +761,7 @@ static int ni_660x_GPCT_winsn(comedi_device *dev,
        lsampl_t * data)
 {
        struct ni_gpct *counter = s->private;
-       return ni_tio_winsn(counter, insn, data);
+       return ni_tio_winsn(devpriv->counter_dev, counter, insn, data);
 }
 
 static int
index 05a23dd8978f49523d75ed2d6be0e07d13de6987..c352315db32456f8a75f4bf419560b7c8565a7bb 100644 (file)
@@ -434,15 +434,15 @@ static int ni_request_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
 
        BUG_ON(gpct_index >= NUM_GPCT);
        comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
-       BUG_ON(devpriv->gpct_mite_chan[gpct_index]);
-       devpriv->gpct_mite_chan[gpct_index] = mite_request_channel(devpriv->mite, devpriv->gpct_mite_ring[gpct_index]);
-       if(devpriv->gpct_mite_chan[gpct_index] == NULL)
+       BUG_ON(devpriv->counter_dev->counters[gpct_index].mite_chan);
+       devpriv->counter_dev->counters[gpct_index].mite_chan = mite_request_channel(devpriv->mite, devpriv->gpct_mite_ring[gpct_index]);
+       if(devpriv->counter_dev->counters[gpct_index].mite_chan == NULL)
        {
                comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
                comedi_error(dev, "failed to reserve mite dma channel for counter.");
                return -EBUSY;
        }
-       ni_set_gpct_dma_channel(dev, gpct_index, devpriv->gpct_mite_chan[gpct_index]->channel);
+       ni_set_gpct_dma_channel(dev, gpct_index, devpriv->counter_dev->counters[gpct_index].mite_chan->channel);
        comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
        return 0;
 }
@@ -492,13 +492,13 @@ void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
 
        BUG_ON(gpct_index >= NUM_GPCT);
        comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
-       if(devpriv->gpct_mite_chan[gpct_index])
+       if(devpriv->counter_dev->counters[gpct_index].mite_chan)
        {
                ni_set_gpct_dma_channel(dev, gpct_index, -1);
-               mite_dma_disarm(devpriv->gpct_mite_chan[gpct_index]);
-               mite_dma_reset(devpriv->gpct_mite_chan[gpct_index]);
-               mite_release_channel(devpriv->gpct_mite_chan[gpct_index]);
-               devpriv->gpct_mite_chan[gpct_index] = NULL;
+               mite_dma_disarm(devpriv->counter_dev->counters[gpct_index].mite_chan);
+               mite_dma_reset(devpriv->counter_dev->counters[gpct_index].mite_chan);
+               mite_release_channel(devpriv->counter_dev->counters[gpct_index].mite_chan);
+               devpriv->counter_dev->counters[gpct_index].mite_chan = NULL;
        }
        comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 #endif // PCIDMA
@@ -778,7 +778,7 @@ static void handle_gpct_interrupt(comedi_device *dev, unsigned short counter_ind
        comedi_subdevice *s = dev->subdevices + NI_GPCT_SUBDEV(counter_index);
 
        comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
-       mite_chan = devpriv->gpct_mite_chan[counter_index];
+       mite_chan = devpriv->counter_dev->counters[counter_index].mite_chan;
        if(mite_chan == NULL)
        {
                comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
@@ -3354,6 +3354,13 @@ static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
 
 static void mio_common_detach(comedi_device *dev)
 {
+       if(dev->private)
+       {
+               if(devpriv->counter_dev)
+               {
+                       ni_gpct_device_destroy(devpriv->counter_dev);
+               }
+       }
        if(dev->subdevices && boardtype.has_8255)
                subdev_8255_cleanup(dev, dev->subdevices + NI_8255_DIO_SUBDEV);
 }
@@ -3440,9 +3447,10 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg)
        return stc_register;
 }
 
-static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
+static void ni_gpct_write_register(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
 {
-       comedi_device *dev = counter->dev;
+       comedi_device *dev = counter_dev->dev;
        unsigned stc_register;
        /* bits in the join reset register which are relevant to counters */
        static const unsigned gpct_joint_reset_mask = G0_Reset | G1_Reset;
@@ -3486,9 +3494,10 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum
        }
 }
 
-static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg)
+static unsigned ni_gpct_read_register(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, enum ni_gpct_register reg)
 {
-       comedi_device *dev = counter->dev;
+       comedi_device *dev = counter_dev->dev;
        unsigned stc_register;
        switch(reg)
        {
@@ -3527,6 +3536,7 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
 {
        comedi_subdevice *s;
        unsigned j;
+       enum ni_gpct_variant counter_variant;
 
        if(boardtype.n_aochan > MAX_N_AO_CHAN)
        {
@@ -3740,6 +3750,16 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        s->insn_config = ni_rtsi_insn_config;
        ni_rtsi_init(dev);
 
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               counter_variant = ni_gpct_variant_m_series;
+       }else
+       {
+               counter_variant = ni_gpct_variant_e_series;
+       }
+       devpriv->counter_dev = ni_gpct_device_construct(dev,
+               &ni_gpct_write_register, &ni_gpct_read_register,
+               counter_variant, NUM_GPCT);
        /* General purpose counters */
        for(j = 0; j < NUM_GPCT; ++j)
        {
@@ -3758,23 +3778,13 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
                s->do_cmdtest = ni_gpct_cmdtest;
                s->cancel = ni_gpct_cancel;
                s->async_dma_dir = DMA_BIDIRECTIONAL;
-               s->private = &devpriv->counters[j];
+               s->private = &devpriv->counter_dev->counters[j];
 
-               devpriv->counters[j].dev = dev;
-               devpriv->counters[j].chip_index = 0;
-               devpriv->counters[j].counter_index = j;
-               devpriv->counters[j].write_register = ni_gpct_write_register;
-               devpriv->counters[j].read_register = ni_gpct_read_register;
-               if(boardtype.reg_type & ni_reg_m_series_mask)
-               {
-                       devpriv->counters[j].variant = ni_gpct_variant_m_series;
-               }else
-               {
-                       devpriv->counters[j].variant = ni_gpct_variant_e_series;
-               }
-               devpriv->counters[j].clock_period_ps = 0;
-               devpriv->counters[j].mite_chan = NULL;
-               ni_tio_init_counter(&devpriv->counters[j]);
+               devpriv->counter_dev->counters[j].chip_index = 0;
+               devpriv->counter_dev->counters[j].counter_index = j;
+               devpriv->counter_dev->counters[j].clock_period_ps = 0;
+               devpriv->counter_dev->counters[j].mite_chan = NULL;
+               ni_tio_init_counter(devpriv->counter_dev, &devpriv->counter_dev->counters[j]);
        }
 
        /* ai configuration */
@@ -4277,52 +4287,62 @@ static int ni_gpct_insn_config(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn, lsampl_t *data)
 {
        struct ni_gpct *counter = s->private;
-       return ni_tio_insn_config(counter, insn, data);
+       return ni_tio_insn_config(devpriv->counter_dev, counter, insn, data);
 }
 
 static int ni_gpct_insn_read(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data)
 {
        struct ni_gpct *counter = s->private;
-       return ni_tio_rinsn(counter, insn, data);
+       return ni_tio_rinsn(devpriv->counter_dev, counter, insn, data);
 }
 
 static int ni_gpct_insn_write(comedi_device *dev, comedi_subdevice *s,
        comedi_insn *insn, lsampl_t *data)
 {
        struct ni_gpct *counter = s->private;
-       return ni_tio_winsn(counter, insn, data);
+       return ni_tio_winsn(devpriv->counter_dev, counter, insn, data);
 }
 
 static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
 {
-// XXX set M_Offset_GX_DMA_Config for m-series
+       int retval;
 #ifdef PCIDMA
+       unsigned long flags;
        struct ni_gpct *counter = s->private;
        const comedi_cmd *cmd = &s->async->cmd;
-       int retval = ni_request_gpct_mite_channel(dev, counter->counter_index);
+
+       retval = ni_request_gpct_mite_channel(dev, counter->counter_index);
        if(retval)
        {
                comedi_error(dev, "no dma channel available for use by counter");
                return retval;
        }
-       return ni_tio_cmd(counter, s->async);
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       retval = ni_tio_cmd(devpriv->counter_dev, counter, s->async);
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 #else
-       return -ENOTSUPP;
+       retval = -ENOTSUPP;
 #endif
+       return retval;
 }
 
 static int ni_gpct_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd)
 {
        struct ni_gpct *counter = s->private;
        //XXX check chanlist_len == 1
-       return ni_tio_cmdtest(counter);
+       return ni_tio_cmdtest(devpriv->counter_dev, counter);
 }
 
 static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s)
 {
        struct ni_gpct *counter = s->private;
-       int retval = ni_tio_cancel(counter);
+       unsigned long flags;
+       int retval;
+
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       retval = ni_tio_cancel(devpriv->counter_dev, counter);
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
        ni_release_gpct_mite_channel(dev, counter->counter_index);
        return retval;
 }
index 89f2b33deb8df25bbeb7a476f895a0d493186952..6dd6d99c13773290c2626f1576d16964ec19d242 100644 (file)
@@ -1354,7 +1354,7 @@ static ni_board ni_boards[];
        unsigned short ao_cmd3;                                 \
        unsigned short ao_trigger_select;                       \
                                                                \
-       struct ni_gpct counters[NUM_GPCT];      \
+       struct ni_gpct_device *counter_dev;     \
        unsigned short an_trig_etc_reg;                         \
                                                                \
        unsigned ai_offset[512];                                \
@@ -1390,7 +1390,6 @@ static ni_board ni_boards[];
        struct mite_struct *mite; \
        struct mite_channel *ai_mite_chan; \
        struct mite_channel *ao_mite_chan;\
-       struct mite_channel *gpct_mite_chan[NUM_GPCT]; \
        struct mite_dma_descriptor_ring *ai_mite_ring; \
        struct mite_dma_descriptor_ring *ao_mite_ring; \
        struct mite_dma_descriptor_ring *gpct_mite_ring[NUM_GPCT];
index 67f3739e764e3cf1e5c1d94b1640f510f8e04fed..33e6a90576427b190b161457cf1be431108926b4 100644 (file)
@@ -48,7 +48,8 @@ DAQ 6601/6602 User Manual (NI 322137B-01)
 #include "mite.h"
 
 static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned generic_clock_source);
-static unsigned ni_tio_generic_clock_src_select(struct ni_gpct *counter);
+static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter);
 
 MODULE_AUTHOR("Comedi <comedi@comedi.org>");
 MODULE_DESCRIPTION("Comedi support for NI general-purpose counters");
@@ -719,9 +720,38 @@ static void __exit ni_tio_cleanup_module(void)
 }
 module_exit(ni_tio_cleanup_module);
 
-static int ni_tio_counting_mode_registers_present(struct ni_gpct *counter)
+struct ni_gpct_device* ni_gpct_device_construct(comedi_device *dev,
+       void (*write_register)(struct ni_gpct_device *this, const struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg),
+       unsigned (*read_register)(struct ni_gpct_device *this, const struct ni_gpct *counter, enum ni_gpct_register reg),
+       enum ni_gpct_variant variant, unsigned num_counters)
+{
+       struct ni_gpct_device *counter_dev = kmalloc(sizeof(struct ni_gpct_device), GFP_KERNEL);
+       if(counter_dev == NULL) return NULL;
+       counter_dev->dev = dev;
+       counter_dev->write_register = write_register;
+       counter_dev->read_register = read_register;
+       counter_dev->variant = variant;
+       BUG_ON(num_counters == 0);
+       counter_dev->counters = kzalloc(sizeof(struct ni_gpct) * num_counters, GFP_KERNEL);
+       if(counter_dev->counters == NULL)
+       {
+               kfree(counter_dev);
+               return NULL;
+       }
+       counter_dev->num_counters = num_counters;
+       return counter_dev;
+}
+
+void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev)
 {
-       switch(counter->variant)
+       if(counter_dev->counters == NULL) return;
+       kfree(counter_dev->counters);
+       kfree(counter_dev);
+}
+
+static int ni_tio_counting_mode_registers_present(const struct ni_gpct_device *counter_dev)
+{
+       switch(counter_dev->variant)
        {
        case ni_gpct_variant_e_series:
                return 0;
@@ -737,9 +767,9 @@ static int ni_tio_counting_mode_registers_present(struct ni_gpct *counter)
        return 0;
 }
 
-static int ni_tio_second_gate_registers_present(struct ni_gpct *counter)
+static int ni_tio_second_gate_registers_present(const struct ni_gpct_device *counter_dev)
 {
-       switch(counter->variant)
+       switch(counter_dev->variant)
        {
        case ni_gpct_variant_e_series:
                return 0;
@@ -755,52 +785,52 @@ static int ni_tio_second_gate_registers_present(struct ni_gpct *counter)
        return 0;
 }
 
-static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter)
+static void ni_tio_reset_count_and_disarm(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter)
 {
-       counter->write_register(counter, Gi_Reset_Bit(counter->counter_index),
+       counter_dev->write_register(counter_dev, counter, Gi_Reset_Bit(counter->counter_index),
                NITIO_Gxx_Joint_Reset_Reg(counter->counter_index));
 }
 
-void ni_tio_init_counter(struct ni_gpct *counter)
+void ni_tio_init_counter(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter)
 {
-       ni_tio_reset_count_and_disarm(counter);
+       ni_tio_reset_count_and_disarm(counter_dev, counter);
        /* initialize counter registers */
-       counter->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)] = 0x0;
-       counter->write_register(counter, counter->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)],
+       counter_dev->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)] = 0x0;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)],
                NITIO_Gi_Autoincrement_Reg(counter->counter_index));
-       counter->regs[NITIO_Gi_Command_Reg(counter->counter_index)] = Gi_Synchronize_Gate_Bit;
-       counter->write_register(counter, counter->regs[NITIO_Gi_Command_Reg(counter->counter_index)],
+       counter_dev->regs[NITIO_Gi_Command_Reg(counter->counter_index)] = Gi_Synchronize_Gate_Bit;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_Command_Reg(counter->counter_index)],
                NITIO_Gi_Command_Reg(counter->counter_index));
-       counter->regs[NITIO_Gi_Mode_Reg(counter->counter_index)] = 0x0;
-       counter->write_register(counter, counter->regs[NITIO_Gi_Mode_Reg(counter->counter_index)],
+       counter_dev->regs[NITIO_Gi_Mode_Reg(counter->counter_index)] = 0x0;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_Mode_Reg(counter->counter_index)],
                NITIO_Gi_Mode_Reg(counter->counter_index));
-       counter->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = 0x0;
-       counter->write_register(counter, counter->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)],
+       counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = 0x0;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)],
                NITIO_Gi_LoadA_Reg(counter->counter_index));
-       counter->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = 0x0;
-       counter->write_register(counter, counter->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)],
+       counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = 0x0;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)],
                NITIO_Gi_LoadB_Reg(counter->counter_index));
-       counter->regs[NITIO_Gi_Input_Select_Reg(counter->counter_index)] = 0x0;
-       counter->write_register(counter, counter->regs[NITIO_Gi_Input_Select_Reg(counter->counter_index)],
+       counter_dev->regs[NITIO_Gi_Input_Select_Reg(counter->counter_index)] = 0x0;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_Input_Select_Reg(counter->counter_index)],
                NITIO_Gi_Input_Select_Reg(counter->counter_index));
-       if(ni_tio_counting_mode_registers_present(counter))
+       if(ni_tio_counting_mode_registers_present(counter_dev))
        {
-               counter->regs[NITIO_Gi_Counting_Mode_Reg(counter->counter_index)] = 0x0;
-               counter->write_register(counter, counter->regs[NITIO_Gi_Counting_Mode_Reg(counter->counter_index)],
+               counter_dev->regs[NITIO_Gi_Counting_Mode_Reg(counter->counter_index)] = 0x0;
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_Counting_Mode_Reg(counter->counter_index)],
                        NITIO_Gi_Counting_Mode_Reg(counter->counter_index));
        }
-       if(ni_tio_second_gate_registers_present(counter))
+       if(ni_tio_second_gate_registers_present(counter_dev))
        {
-               counter->regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)] = 0x0;
-               counter->write_register(counter, counter->regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)],
+               counter_dev->regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)] = 0x0;
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)],
                        NITIO_Gi_Second_Gate_Reg(counter->counter_index));
        }
 }
 
-static lsampl_t ni_tio_counter_status(struct ni_gpct *counter)
+static lsampl_t ni_tio_counter_status(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter)
 {
        lsampl_t status = 0;
-       const unsigned bits = counter->read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index));
+       const unsigned bits = counter_dev->read_register(counter_dev, counter, NITIO_Gxx_Status_Reg(counter->counter_index));
        if(bits & Gi_Armed_Bit(counter->counter_index))
        {
                status |= COMEDI_COUNTER_ARMED;
@@ -810,15 +840,17 @@ static lsampl_t ni_tio_counter_status(struct ni_gpct *counter)
        return status;
 }
 
-static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
+static void ni_tio_set_sync_mode(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter,
+       int force_alt_sync)
 {
        const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index);
        static const uint64_t min_normal_sync_period_ps = 25000;
-       const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter, ni_tio_generic_clock_src_select(counter));
+       const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter,
+               ni_tio_generic_clock_src_select(counter_dev, counter));
 
-       if(ni_tio_counting_mode_registers_present(counter) == 0) return;
+       if(ni_tio_counting_mode_registers_present(counter_dev) == 0) return;
 
-       switch(counter->regs[counting_mode_reg] & Gi_Counting_Mode_Mask)
+       switch(counter_dev->regs[counting_mode_reg] & Gi_Counting_Mode_Mask)
        {
        case Gi_Counting_Mode_QuadratureX1_Bits:
        case Gi_Counting_Mode_QuadratureX2_Bits:
@@ -835,15 +867,16 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
        if(force_alt_sync ||
                (clock_period_ps && clock_period_ps < min_normal_sync_period_ps))
        {
-               counter->regs[counting_mode_reg] |= Gi_Alternate_Sync_Bit(counter->variant);
+               counter_dev->regs[counting_mode_reg] |= Gi_Alternate_Sync_Bit(counter_dev->variant);
        }else
        {
-               counter->regs[counting_mode_reg] &= ~Gi_Alternate_Sync_Bit(counter->variant);
+               counter_dev->regs[counting_mode_reg] &= ~Gi_Alternate_Sync_Bit(counter_dev->variant);
        }
-       counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[counting_mode_reg], counting_mode_reg);
 }
 
-static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
+static int ni_tio_set_counter_mode(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, unsigned mode)
 {
        const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index);
        const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index);
@@ -859,69 +892,70 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
        switch(mode & NI_GPCT_RELOAD_SOURCE_MASK)
        {
        case NI_GPCT_RELOAD_SOURCE_FIXED_BITS:
-               counter->regs[mode_reg] &= ~Gi_Reload_Source_Switching_Bit;
-               counter->regs[input_select_reg] &= ~Gi_Gate_Select_Load_Source_Bit;
+               counter_dev->regs[mode_reg] &= ~Gi_Reload_Source_Switching_Bit;
+               counter_dev->regs[input_select_reg] &= ~Gi_Gate_Select_Load_Source_Bit;
                break;
        case NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS:
-               counter->regs[mode_reg] |= Gi_Reload_Source_Switching_Bit;
-               counter->regs[input_select_reg] &= ~Gi_Gate_Select_Load_Source_Bit;
+               counter_dev->regs[mode_reg] |= Gi_Reload_Source_Switching_Bit;
+               counter_dev->regs[input_select_reg] &= ~Gi_Gate_Select_Load_Source_Bit;
                break;
        case NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS:
-               counter->regs[input_select_reg] |= Gi_Gate_Select_Load_Source_Bit;
-               counter->regs[mode_reg] &= ~(Gi_Reload_Source_Switching_Bit | Gi_Gating_Mode_Mask);
-               counter->regs[mode_reg] |= Gi_Level_Gating_Bits;
+               counter_dev->regs[input_select_reg] |= Gi_Gate_Select_Load_Source_Bit;
+               counter_dev->regs[mode_reg] &= ~(Gi_Reload_Source_Switching_Bit | Gi_Gating_Mode_Mask);
+               counter_dev->regs[mode_reg] |= Gi_Level_Gating_Bits;
                break;
        default:
                break;
        }
 
-       counter->regs[mode_reg] &= ~mode_reg_direct_mask;
-       counter->regs[mode_reg] |= mode & mode_reg_direct_mask;
-       counter->write_register(counter, counter->regs[mode_reg], mode_reg);
+       counter_dev->regs[mode_reg] &= ~mode_reg_direct_mask;
+       counter_dev->regs[mode_reg] |= mode & mode_reg_direct_mask;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[mode_reg], mode_reg);
 
-       if(ni_tio_counting_mode_registers_present(counter))
+       if(ni_tio_counting_mode_registers_present(counter_dev))
        {
-               counter->regs[counting_mode_reg] &= ~Gi_Counting_Mode_Mask;
-               counter->regs[counting_mode_reg] |= (mode >> NI_GPCT_COUNTING_MODE_SHIFT) & Gi_Counting_Mode_Mask;
-               counter->regs[counting_mode_reg] &= ~Gi_Index_Phase_Mask;
-               counter->regs[counting_mode_reg] |= ((mode >> NI_GPCT_INDEX_PHASE_BITSHIFT) << Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask;
+               counter_dev->regs[counting_mode_reg] &= ~Gi_Counting_Mode_Mask;
+               counter_dev->regs[counting_mode_reg] |= (mode >> NI_GPCT_COUNTING_MODE_SHIFT) & Gi_Counting_Mode_Mask;
+               counter_dev->regs[counting_mode_reg] &= ~Gi_Index_Phase_Mask;
+               counter_dev->regs[counting_mode_reg] |= ((mode >> NI_GPCT_INDEX_PHASE_BITSHIFT) << Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask;
                if(mode & NI_GPCT_INDEX_ENABLE_BIT)
                {
-                       counter->regs[counting_mode_reg] |= Gi_Index_Mode_Bit;
+                       counter_dev->regs[counting_mode_reg] |= Gi_Index_Mode_Bit;
                }else
                {
-                       counter->regs[counting_mode_reg] &= ~Gi_Index_Mode_Bit;
+                       counter_dev->regs[counting_mode_reg] &= ~Gi_Index_Mode_Bit;
                }
-               counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg);
-               ni_tio_set_sync_mode(counter, 0);
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[counting_mode_reg], counting_mode_reg);
+               ni_tio_set_sync_mode(counter_dev, counter, 0);
        }
 
-       counter->regs[command_reg] &= ~Gi_Up_Down_Mask;
-       counter->regs[command_reg] |= ((mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) << Gi_Up_Down_Shift) & Gi_Up_Down_Mask;
-       counter->write_register(counter, counter->regs[command_reg], command_reg);
+       counter_dev->regs[command_reg] &= ~Gi_Up_Down_Mask;
+       counter_dev->regs[command_reg] |= ((mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) << Gi_Up_Down_Shift) & Gi_Up_Down_Mask;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[command_reg], command_reg);
 
        if(mode & NI_GPCT_OR_GATE_BIT)
        {
-               counter->regs[input_select_reg] |= Gi_Or_Gate_Bit;
+               counter_dev->regs[input_select_reg] |= Gi_Or_Gate_Bit;
        }else
        {
-               counter->regs[input_select_reg] &= ~Gi_Or_Gate_Bit;
+               counter_dev->regs[input_select_reg] &= ~Gi_Or_Gate_Bit;
        }
        if(mode & NI_GPCT_INVERT_OUTPUT_BIT)
        {
-               counter->regs[input_select_reg] |= Gi_Output_Polarity_Bit;
+               counter_dev->regs[input_select_reg] |= Gi_Output_Polarity_Bit;
        }else
        {
-               counter->regs[input_select_reg] &= ~Gi_Output_Polarity_Bit;
+               counter_dev->regs[input_select_reg] &= ~Gi_Output_Polarity_Bit;
        }
-       counter->write_register(counter, counter->regs[input_select_reg], input_select_reg);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[input_select_reg], input_select_reg);
 
        return 0;
 }
 
-static int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
+static int ni_tio_arm(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter,
+       int arm, unsigned start_trigger)
 {
-       unsigned command_bits = counter->regs[NITIO_Gi_Command_Reg(counter->counter_index)];
+       unsigned command_bits = counter_dev->regs[NITIO_Gi_Command_Reg(counter->counter_index)];
        if(arm)
        {
                switch(start_trigger)
@@ -935,14 +969,14 @@ static int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
                default:
                        break;
                }
-               if(ni_tio_counting_mode_registers_present(counter))
+               if(ni_tio_counting_mode_registers_present(counter_dev))
                {
                        const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index);
                        switch(start_trigger)
                        {
                        case NI_GPCT_ARM_IMMEDIATE:
                        case NI_GPCT_ARM_PAIRED_IMMEDIATE:
-                               counter->regs[counting_mode_reg] &= ~Gi_HW_Arm_Enable_Bit;
+                               counter_dev->regs[counting_mode_reg] &= ~Gi_HW_Arm_Enable_Bit;
                                break;
                        default:
                                if(start_trigger & NI_GPCT_ARM_UNKNOWN)
@@ -950,10 +984,10 @@ static int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
                                        /* pass-through the least significant bits so we can figure out what select later */
                                        unsigned hw_arm_select_bits;
 
-                                       counter->regs[counting_mode_reg] &= ~Gi_HW_Arm_Select_Mask(counter->variant);
-                                       hw_arm_select_bits = (start_trigger << Gi_HW_Arm_Select_Shift) & Gi_HW_Arm_Select_Mask(counter->variant);
-                                       counter->regs[counting_mode_reg] |= Gi_HW_Arm_Enable_Bit | hw_arm_select_bits;
-                                       counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg);
+                                       counter_dev->regs[counting_mode_reg] &= ~Gi_HW_Arm_Select_Mask(counter_dev->variant);
+                                       hw_arm_select_bits = (start_trigger << Gi_HW_Arm_Select_Shift) & Gi_HW_Arm_Select_Mask(counter_dev->variant);
+                                       counter_dev->regs[counting_mode_reg] |= Gi_HW_Arm_Enable_Bit | hw_arm_select_bits;
+                                       counter_dev->write_register(counter_dev, counter, counter_dev->regs[counting_mode_reg], counting_mode_reg);
                                }else
                                {
                                        return -EINVAL;
@@ -965,7 +999,7 @@ static int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
        {
                command_bits |= Gi_Disarm_Bit;
        }
-       counter->write_register(counter, command_bits, NITIO_Gi_Command_Reg(counter->counter_index));
+       counter_dev->write_register(counter_dev, counter, command_bits, NITIO_Gi_Command_Reg(counter->counter_index));
        return 0;
 }
 
@@ -1085,58 +1119,60 @@ static unsigned ni_m_series_source_select_bits(lsampl_t clock_source)
        return Gi_Source_Select_Bits(ni_m_series_clock);
 };
 
-static void ni_tio_set_source_subselect(struct ni_gpct *counter, lsampl_t clock_source)
+static void ni_tio_set_source_subselect(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, lsampl_t clock_source)
 {
        const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index);
 
-       if(counter->variant != ni_gpct_variant_m_series) return;
+       if(counter_dev->variant != ni_gpct_variant_m_series) return;
        switch(clock_source & NI_GPCT_CLOCK_SRC_SELECT_MASK)
        {
        /* Gi_Source_Subselect is zero */
        case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS:
        case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS:
-               counter->regs[second_gate_reg] &= ~Gi_Source_Subselect_Bit;
+               counter_dev->regs[second_gate_reg] &= ~Gi_Source_Subselect_Bit;
                break;
        /* Gi_Source_Subselect is one */
        case NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS:
        case NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS:
-               counter->regs[second_gate_reg] |= Gi_Source_Subselect_Bit;
+               counter_dev->regs[second_gate_reg] |= Gi_Source_Subselect_Bit;
                break;
        /* Gi_Source_Subselect doesn't matter */
        default:
                return;
                break;
        }
-       counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[second_gate_reg], second_gate_reg);
 }
 
-static int ni_tio_set_clock_src(struct ni_gpct *counter, lsampl_t clock_source, lsampl_t period_ns)
+static int ni_tio_set_clock_src(struct ni_gpct_device *counter_dev, struct ni_gpct *counter,
+       lsampl_t clock_source, lsampl_t period_ns)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        static const uint64_t pico_per_nano = 1000;
 
 /*FIXME: validate clock source */
-       counter->regs[input_select_reg] &= ~Gi_Source_Select_Mask;
-       switch(counter->variant)
+       counter_dev->regs[input_select_reg] &= ~Gi_Source_Select_Mask;
+       switch(counter_dev->variant)
        {
        case ni_gpct_variant_660x:
-               counter->regs[input_select_reg] |= ni_660x_source_select_bits(clock_source);
+               counter_dev->regs[input_select_reg] |= ni_660x_source_select_bits(clock_source);
                break;
        case ni_gpct_variant_e_series:
        case ni_gpct_variant_m_series:
-               counter->regs[input_select_reg] |= ni_m_series_source_select_bits(clock_source);
+               counter_dev->regs[input_select_reg] |= ni_m_series_source_select_bits(clock_source);
                break;
        default:
                BUG();
                break;
        }
        if(clock_source & NI_GPCT_INVERT_CLOCK_SRC_BIT)
-               counter->regs[input_select_reg] |= Gi_Source_Polarity_Bit;
+               counter_dev->regs[input_select_reg] |= Gi_Source_Polarity_Bit;
        else
-               counter->regs[input_select_reg] &= ~Gi_Source_Polarity_Bit;
-       counter->write_register(counter, counter->regs[input_select_reg], input_select_reg);
-       ni_tio_set_source_subselect(counter, clock_source);
-       if(ni_tio_counting_mode_registers_present(counter))
+               counter_dev->regs[input_select_reg] &= ~Gi_Source_Polarity_Bit;
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[input_select_reg], input_select_reg);
+       ni_tio_set_source_subselect(counter_dev, counter, clock_source);
+       if(ni_tio_counting_mode_registers_present(counter_dev))
        {
                const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index);
                const unsigned prescaling_mode = clock_source & NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK;
@@ -1144,49 +1180,51 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, lsampl_t clock_source,
                switch(prescaling_mode)
                {
                case NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS:
-                       counter->regs[counting_mode_reg] &= ~(Gi_Prescale_X2_Bit(counter->variant) | Gi_Prescale_X8_Bit(counter->variant));
+                       counter_dev->regs[counting_mode_reg] &= ~(Gi_Prescale_X2_Bit(counter_dev->variant) | Gi_Prescale_X8_Bit(counter_dev->variant));
                        break;
                case NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS:
-                       counter->regs[counting_mode_reg] |= Gi_Prescale_X2_Bit(counter->variant);
-                       counter->regs[counting_mode_reg] &= ~Gi_Prescale_X8_Bit(counter->variant);
+                       counter_dev->regs[counting_mode_reg] |= Gi_Prescale_X2_Bit(counter_dev->variant);
+                       counter_dev->regs[counting_mode_reg] &= ~Gi_Prescale_X8_Bit(counter_dev->variant);
                        break;
                case NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS:
-                       counter->regs[counting_mode_reg] |= Gi_Prescale_X8_Bit(counter->variant);
-                       counter->regs[counting_mode_reg] &= ~Gi_Prescale_X2_Bit(counter->variant);
+                       counter_dev->regs[counting_mode_reg] |= Gi_Prescale_X8_Bit(counter_dev->variant);
+                       counter_dev->regs[counting_mode_reg] &= ~Gi_Prescale_X2_Bit(counter_dev->variant);
                        break;
                default:
                        return -EINVAL;
                        break;
                }
-               counter->write_register(counter, counter->regs[counting_mode_reg], counting_mode_reg);
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[counting_mode_reg], counting_mode_reg);
        }
        counter->clock_period_ps = pico_per_nano * period_ns;
-       ni_tio_set_sync_mode(counter, 0);
+       ni_tio_set_sync_mode(counter_dev, counter, 0);
        return 0;
 }
 
-static unsigned ni_tio_clock_src_modifiers(struct ni_gpct *counter)
+static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        const unsigned counting_mode_reg = NITIO_Gi_Counting_Mode_Reg(counter->counter_index);
        unsigned bits = 0;
 
-       if(counter->regs[input_select_reg] & Gi_Source_Polarity_Bit)
+       if(counter_dev->regs[input_select_reg] & Gi_Source_Polarity_Bit)
                bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT;
-       if(counter->regs[counting_mode_reg] & Gi_Prescale_X2_Bit(counter->variant))
+       if(counter_dev->regs[counting_mode_reg] & Gi_Prescale_X2_Bit(counter_dev->variant))
                bits |= NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS;
-       if(counter->regs[counting_mode_reg] & Gi_Prescale_X8_Bit(counter->variant))
+       if(counter_dev->regs[counting_mode_reg] & Gi_Prescale_X8_Bit(counter_dev->variant))
                bits |= NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS;
        return bits;
 }
 
-static unsigned ni_m_series_clock_src_select(struct ni_gpct *counter)
+static unsigned ni_m_series_clock_src_select(const struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index);
        unsigned clock_source = 0;
        unsigned i;
-       const unsigned input_select = (counter->regs[input_select_reg] & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
+       const unsigned input_select = (counter_dev->regs[input_select_reg] & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
 
        switch(input_select)
        {
@@ -1197,7 +1235,7 @@ static unsigned ni_m_series_clock_src_select(struct ni_gpct *counter)
                clock_source = NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS;
                break;
        case NI_M_Series_Timebase_3_Clock:
-               if(counter->regs[second_gate_reg] & Gi_Source_Subselect_Bit)
+               if(counter_dev->regs[second_gate_reg] & Gi_Source_Subselect_Bit)
                        clock_source = NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS;
                else
                        clock_source = NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS;
@@ -1206,7 +1244,7 @@ static unsigned ni_m_series_clock_src_select(struct ni_gpct *counter)
                clock_source = NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS;
                break;
        case NI_M_Series_Next_Gate_Clock:
-               if(counter->regs[second_gate_reg] & Gi_Source_Subselect_Bit)
+               if(counter_dev->regs[second_gate_reg] & Gi_Source_Subselect_Bit)
                        clock_source = NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS;
                else
                        clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS;
@@ -1239,16 +1277,17 @@ static unsigned ni_m_series_clock_src_select(struct ni_gpct *counter)
                BUG();
                break;
        }
-       clock_source |= ni_tio_clock_src_modifiers(counter);
+       clock_source |= ni_tio_clock_src_modifiers(counter_dev, counter);
        return clock_source;
 }
 
-static unsigned ni_660x_clock_src_select(struct ni_gpct *counter)
+static unsigned ni_660x_clock_src_select(const struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        unsigned clock_source = 0;
        unsigned i;
-       const unsigned input_select = (counter->regs[input_select_reg] & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
+       const unsigned input_select = (counter_dev->regs[input_select_reg] & Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
 
        switch(input_select)
        {
@@ -1295,20 +1334,21 @@ static unsigned ni_660x_clock_src_select(struct ni_gpct *counter)
                BUG();
                break;
        }
-       clock_source |= ni_tio_clock_src_modifiers(counter);
+       clock_source |= ni_tio_clock_src_modifiers(counter_dev, counter);
        return clock_source;
 }
 
-static unsigned ni_tio_generic_clock_src_select(struct ni_gpct *counter)
+static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter)
 {
-       switch(counter->variant)
+       switch(counter_dev->variant)
        {
        case ni_gpct_variant_e_series:
        case ni_gpct_variant_m_series:
-               return ni_m_series_clock_src_select(counter);
+               return ni_m_series_clock_src_select(counter_dev, counter);
                break;
        case ni_gpct_variant_660x:
-               return ni_660x_clock_src_select(counter);
+               return ni_660x_clock_src_select(counter_dev, counter);
                break;
        default:
                BUG();
@@ -1358,39 +1398,42 @@ static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned g
        return clock_period_ps;
 }
 
-static void ni_tio_get_clock_src(struct ni_gpct *counter, lsampl_t *clock_source, lsampl_t *period_ns)
+static void ni_tio_get_clock_src(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter,
+       lsampl_t *clock_source, lsampl_t *period_ns)
 {
        static const unsigned pico_per_nano = 1000;
        uint64_t temp64;
-       *clock_source = ni_tio_generic_clock_src_select(counter);
+       *clock_source = ni_tio_generic_clock_src_select(counter_dev, counter);
        temp64 = ni_tio_clock_period_ps(counter, *clock_source);
        do_div(temp64, pico_per_nano);
        *period_ns = temp64;
 }
 
-static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, lsampl_t gate_source)
+static void ni_tio_set_first_gate_modifiers(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, lsampl_t gate_source)
 {
        const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index);
 
        if(gate_source & CR_INVERT)
        {
-               counter->regs[mode_reg] |= Gi_Gate_Polarity_Bit;
+               counter_dev->regs[mode_reg] |= Gi_Gate_Polarity_Bit;
        }else
        {
-               counter->regs[mode_reg] &= ~Gi_Gate_Polarity_Bit;
+               counter_dev->regs[mode_reg] &= ~Gi_Gate_Polarity_Bit;
        }
-       counter->regs[mode_reg] &= ~Gi_Gating_Mode_Mask;
+       counter_dev->regs[mode_reg] &= ~Gi_Gating_Mode_Mask;
        if(gate_source & CR_EDGE)
        {
-               counter->regs[mode_reg] |= Gi_Level_Gating_Bits;
+               counter_dev->regs[mode_reg] |= Gi_Level_Gating_Bits;
        }else
        {
-               counter->regs[mode_reg] |= Gi_Rising_Edge_Gating_Bits;
+               counter_dev->regs[mode_reg] |= Gi_Rising_Edge_Gating_Bits;
        }
-       counter->write_register(counter, counter->regs[mode_reg], mode_reg);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[mode_reg], mode_reg);
 }
 
-static int ni_660x_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source)
+static int ni_660x_set_first_gate(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, lsampl_t gate_source)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        const unsigned selected_gate = CR_CHAN(gate_source);
@@ -1432,13 +1475,14 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source)
                return -EINVAL;
                break;
        }
-       counter->regs[input_select_reg] &= ~Gi_Gate_Select_Mask;
-       counter->regs[input_select_reg] |= Gi_Gate_Select_Bits(ni_660x_gate_select);
-       counter->write_register(counter, counter->regs[input_select_reg], input_select_reg);
+       counter_dev->regs[input_select_reg] &= ~Gi_Gate_Select_Mask;
+       counter_dev->regs[input_select_reg] |= Gi_Gate_Select_Bits(ni_660x_gate_select);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[input_select_reg], input_select_reg);
        return 0;
 }
 
-static int ni_m_series_set_first_gate(struct ni_gpct *counter, lsampl_t gate_source)
+static int ni_m_series_set_first_gate(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, lsampl_t gate_source)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        const unsigned selected_gate = CR_CHAN(gate_source);
@@ -1480,13 +1524,14 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter, lsampl_t gate_sou
                return -EINVAL;
                break;
        }
-       counter->regs[input_select_reg] &= ~Gi_Gate_Select_Mask;
-       counter->regs[input_select_reg] |= Gi_Gate_Select_Bits(ni_m_series_gate_select);
-       counter->write_register(counter, counter->regs[input_select_reg], input_select_reg);
+       counter_dev->regs[input_select_reg] &= ~Gi_Gate_Select_Mask;
+       counter_dev->regs[input_select_reg] |= Gi_Gate_Select_Bits(ni_m_series_gate_select);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[input_select_reg], input_select_reg);
        return 0;
 }
 
-static int ni_660x_set_second_gate(struct ni_gpct *counter, lsampl_t gate_source)
+static int ni_660x_set_second_gate(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, lsampl_t gate_source)
 {
        const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index);
        const unsigned selected_second_gate = CR_CHAN(gate_source);
@@ -1529,14 +1574,15 @@ static int ni_660x_set_second_gate(struct ni_gpct *counter, lsampl_t gate_source
                return -EINVAL;
                break;
        };
-       counter->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit;
-       counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask;
-       counter->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_660x_second_gate_select);
-       counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg);
+       counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit;
+       counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask;
+       counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_660x_second_gate_select);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[second_gate_reg], second_gate_reg);
        return 0;
 }
 
-static int ni_m_series_set_second_gate(struct ni_gpct *counter, lsampl_t gate_source)
+static int ni_m_series_set_second_gate(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, lsampl_t gate_source)
 {
        const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index);
        const unsigned selected_second_gate = CR_CHAN(gate_source);
@@ -1552,14 +1598,15 @@ static int ni_m_series_set_second_gate(struct ni_gpct *counter, lsampl_t gate_so
                ni_m_series_second_gate_select = selected_second_gate & selected_second_gate_mask;
                break;
        };
-       counter->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit;
-       counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask;
-       counter->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_m_series_second_gate_select);
-       counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg);
+       counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Mode_Bit;
+       counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Select_Mask;
+       counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Select_Bits(ni_m_series_second_gate_select);
+       counter_dev->write_register(counter_dev, counter, counter_dev->regs[second_gate_reg], second_gate_reg);
        return 0;
 }
 
-static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsampl_t gate_source)
+static int ni_tio_set_gate_src(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, unsigned gate_index, lsampl_t gate_source)
 {
        const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index);
        const unsigned second_gate_reg = NITIO_Gi_Second_Gate_Reg(counter->counter_index);
@@ -1569,20 +1616,20 @@ static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
        case 0:
                if(CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT)
                {
-                       counter->regs[mode_reg] &= ~Gi_Gating_Mode_Mask;
-                       counter->regs[mode_reg] |= Gi_Gating_Disabled_Bits;
-                       counter->write_register(counter, counter->regs[mode_reg], mode_reg);
+                       counter_dev->regs[mode_reg] &= ~Gi_Gating_Mode_Mask;
+                       counter_dev->regs[mode_reg] |= Gi_Gating_Disabled_Bits;
+                       counter_dev->write_register(counter_dev, counter, counter_dev->regs[mode_reg], mode_reg);
                        return 0;
                }
-               ni_tio_set_first_gate_modifiers(counter, gate_source);
-               switch(counter->variant)
+               ni_tio_set_first_gate_modifiers(counter_dev, counter, gate_source);
+               switch(counter_dev->variant)
                {
                case ni_gpct_variant_e_series:
                case ni_gpct_variant_m_series:
-                       return ni_m_series_set_first_gate(counter, gate_source);
+                       return ni_m_series_set_first_gate(counter_dev, counter, gate_source);
                        break;
                case ni_gpct_variant_660x:
-                       return ni_660x_set_first_gate(counter, gate_source);
+                       return ni_660x_set_first_gate(counter_dev, counter, gate_source);
                        break;
                default:
                        BUG();
@@ -1590,27 +1637,27 @@ static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
                }
                break;
        case 1:
-               if(ni_tio_second_gate_registers_present(counter) == 0) return -EINVAL;
+               if(ni_tio_second_gate_registers_present(counter_dev) == 0) return -EINVAL;
                if(CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT)
                {
-                       counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Mode_Bit;
-                       counter->write_register(counter, counter->regs[second_gate_reg], second_gate_reg);
+                       counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Mode_Bit;
+                       counter_dev->write_register(counter_dev, counter, counter_dev->regs[second_gate_reg], second_gate_reg);
                        return 0;
                }
                if(gate_source & CR_INVERT)
                {
-                       counter->regs[second_gate_reg] |= Gi_Second_Gate_Polarity_Bit;
+                       counter_dev->regs[second_gate_reg] |= Gi_Second_Gate_Polarity_Bit;
                }else
                {
-                       counter->regs[second_gate_reg] &= ~Gi_Second_Gate_Polarity_Bit;
+                       counter_dev->regs[second_gate_reg] &= ~Gi_Second_Gate_Polarity_Bit;
                }
-               switch(counter->variant)
+               switch(counter_dev->variant)
                {
                case ni_gpct_variant_m_series:
-                       return ni_m_series_set_second_gate(counter, gate_source);
+                       return ni_m_series_set_second_gate(counter_dev, counter, gate_source);
                        break;
                case ni_gpct_variant_660x:
-                       return ni_660x_set_second_gate(counter, gate_source);
+                       return ni_660x_set_second_gate(counter_dev, counter, gate_source);
                        break;
                default:
                        BUG();
@@ -1624,36 +1671,38 @@ static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
        return 0;
 }
 
-static int ni_tio_set_other_src(struct ni_gpct *counter, 
-                               unsigned index, lsampl_t source)
+static int ni_tio_set_other_src(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, unsigned index, lsampl_t source)
 {
-       if (counter->variant == ni_gpct_variant_m_series && 
-           (index == NI_GPCT_SOURCE_ENCODER_A ||
-            index == NI_GPCT_SOURCE_ENCODER_B ||
-            index == NI_GPCT_SOURCE_ENCODER_Z)) {
-               unsigned int abz_reg, shift, mask;
-               abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index);
+       if(counter_dev->variant == ni_gpct_variant_m_series)
+       {
+               unsigned int abz_reg, shift, mask;
 
+               abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index);
                switch(index) {
                case NI_GPCT_SOURCE_ENCODER_A:
-                       shift = 10;
+                       shift = 10;
                        break;
                case NI_GPCT_SOURCE_ENCODER_B:
-                       shift = 5;
+                       shift = 5;
                        break;
                case NI_GPCT_SOURCE_ENCODER_Z:
-                       shift = 0;
+                       shift = 0;
+                       break;
+               default:
+                       return -EINVAL;
                        break;
                }
                mask = 0x1f << shift;
-               if (source > 0x1f) {
-                 /* Disable gate */
-                 source = 0x1f;
+               if(source > 0x1f)
+               {
+                       /* Disable gate */
+                       source = 0x1f;
                }
-               counter->regs[abz_reg] &= ~mask;
-               counter->regs[abz_reg] |= source << shift;
-               counter->write_register(counter, counter->regs[abz_reg], abz_reg);
-               printk("%s %x %d %d\n", __FUNCTION__, counter->regs[abz_reg], index, source);
+               counter_dev->regs[abz_reg] &= ~mask;
+               counter_dev->regs[abz_reg] |= (source << shift) & mask;
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[abz_reg], abz_reg);
+//             rt_printk("%s %x %d %d\n", __FUNCTION__, counter_dev->regs[abz_reg], index, source);
                return 0;
        }
        return -EINVAL;
@@ -1813,7 +1862,8 @@ static unsigned ni_m_series_second_gate_to_generic_gate_source(unsigned ni_m_ser
        return 0;
 };
 
-static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, lsampl_t *gate_source)
+static int ni_tio_get_gate_src(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, unsigned gate_index, lsampl_t *gate_source)
 {
        const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
        const unsigned mode_reg = NITIO_Gi_Mode_Reg(counter->counter_index);
@@ -1823,15 +1873,15 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
        switch(gate_index)
        {
        case 0:
-               if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits)
+               if((counter_dev->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits)
                {
                        *gate_source = NI_GPCT_DISABLED_GATE_SELECT;
                        return 0;
                }else
                {
-                       gate_select_bits = (counter->regs[input_select_reg] & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift;
+                       gate_select_bits = (counter_dev->regs[input_select_reg] & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift;
                }
-               switch(counter->variant)
+               switch(counter_dev->variant)
                {
                case ni_gpct_variant_e_series:
                case ni_gpct_variant_m_series:
@@ -1844,26 +1894,26 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
                        BUG();
                        break;
                }
-               if(counter->regs[input_select_reg] & Gi_Gate_Polarity_Bit)
+               if(counter_dev->regs[input_select_reg] & Gi_Gate_Polarity_Bit)
                {
                        *gate_source |= CR_INVERT;
                }
-               if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
+               if((counter_dev->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
                {
                        *gate_source |= CR_EDGE;
                }
                break;
        case 1:
-               if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits ||
-                       (counter->regs[second_gate_reg] & Gi_Second_Gate_Mode_Bit) == 0)
+               if((counter_dev->regs[mode_reg] & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits ||
+                       (counter_dev->regs[second_gate_reg] & Gi_Second_Gate_Mode_Bit) == 0)
                {
                        *gate_source = NI_GPCT_DISABLED_GATE_SELECT;
                        return 0;
                }else
                {
-                       gate_select_bits = (counter->regs[second_gate_reg] & Gi_Second_Gate_Select_Mask) >> Gi_Second_Gate_Select_Shift;
+                       gate_select_bits = (counter_dev->regs[second_gate_reg] & Gi_Second_Gate_Select_Mask) >> Gi_Second_Gate_Select_Shift;
                }
-               switch(counter->variant)
+               switch(counter_dev->variant)
                {
                case ni_gpct_variant_e_series:
                case ni_gpct_variant_m_series:
@@ -1876,12 +1926,12 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
                        BUG();
                        break;
                }
-               if(counter->regs[second_gate_reg] & Gi_Second_Gate_Polarity_Bit)
+               if(counter_dev->regs[second_gate_reg] & Gi_Second_Gate_Polarity_Bit)
                {
                        *gate_source |= CR_INVERT;
                }
                /* second gate can't have edge/level mode set independently */
-               if((counter->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
+               if((counter_dev->regs[mode_reg] & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
                {
                        *gate_source |= CR_EDGE;
                }
@@ -1893,45 +1943,44 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, lsa
        return 0;
 }
 
-int ni_tio_insn_config(struct ni_gpct *counter,
-       comedi_insn *insn,
-       lsampl_t *data)
+int ni_tio_insn_config(struct ni_gpct_device *counter_dev, struct ni_gpct *counter,
+       comedi_insn *insn, lsampl_t *data)
 {
        switch(data[0])
        {
        case INSN_CONFIG_SET_COUNTER_MODE:
-               return ni_tio_set_counter_mode(counter, data[1]);
+               return ni_tio_set_counter_mode(counter_dev, counter, data[1]);
                break;
        case INSN_CONFIG_ARM:
-               return ni_tio_arm(counter, 1, data[1]);
+               return ni_tio_arm(counter_dev, counter, 1, data[1]);
                break;
        case INSN_CONFIG_DISARM:
-               ni_tio_arm(counter, 0, 0);
+               ni_tio_arm(counter_dev, counter, 0, 0);
                return 0;
                break;
        case INSN_CONFIG_GET_COUNTER_STATUS:
-               data[1] = ni_tio_counter_status(counter);
+               data[1] = ni_tio_counter_status(counter_dev, counter);
                data[2] = counter_status_mask;
                return 0;
                break;
        case INSN_CONFIG_SET_CLOCK_SRC:
-               return ni_tio_set_clock_src(counter, data[1], data[2]);
+               return ni_tio_set_clock_src(counter_dev, counter, data[1], data[2]);
                break;
        case INSN_CONFIG_GET_CLOCK_SRC:
-               ni_tio_get_clock_src(counter, &data[1], &data[2]);
+               ni_tio_get_clock_src(counter_dev, counter, &data[1], &data[2]);
                return 0;
                break;
        case INSN_CONFIG_SET_GATE_SRC:
-               return ni_tio_set_gate_src(counter, data[1], data[2]);
+               return ni_tio_set_gate_src(counter_dev, counter, data[1], data[2]);
                break;
        case INSN_CONFIG_GET_GATE_SRC:
-               return ni_tio_get_gate_src(counter, data[1], &data[2]);
+               return ni_tio_get_gate_src(counter_dev, counter, data[1], &data[2]);
                break;
        case INSN_CONFIG_SET_OTHER_SRC:
-               return ni_tio_set_other_src(counter, data[1], data[2]);
+               return ni_tio_set_other_src(counter_dev, counter, data[1], data[2]);
                break;
        case INSN_CONFIG_RESET:
-               ni_tio_reset_count_and_disarm(counter);
+               ni_tio_reset_count_and_disarm(counter_dev, counter);
                return 0;
                break;
        default:
@@ -1940,9 +1989,8 @@ int ni_tio_insn_config(struct ni_gpct *counter,
        return -EINVAL;
 }
 
-int ni_tio_rinsn(struct ni_gpct *counter,
-       comedi_insn *insn,
-       lsampl_t *data)
+int ni_tio_rinsn(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter,
+       comedi_insn *insn, lsampl_t *data)
 {
        const unsigned command_reg = NITIO_Gi_Command_Reg(counter->counter_index);
        const unsigned channel = CR_CHAN(insn->chanspec);
@@ -1954,37 +2002,37 @@ int ni_tio_rinsn(struct ni_gpct *counter,
        switch(channel)
        {
        case 0:
-               counter->regs[command_reg] &= ~Gi_Save_Trace_Bit;
-               counter->write_register(counter, counter->regs[command_reg], command_reg);
-               counter->write_register(counter, counter->regs[command_reg] | Gi_Save_Trace_Bit,
+               counter_dev->regs[command_reg] &= ~Gi_Save_Trace_Bit;
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[command_reg], command_reg);
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[command_reg] | Gi_Save_Trace_Bit,
                        command_reg);
                /* The count doesn't get latched until the next clock edge, so it is possible the count
                may change (once) while we are reading.  Since the read of the SW_Save_Reg isn't
                atomic (apparently even when it's a 32 bit register according to 660x docs),
                we need to read twice and make sure the reading hasn't changed.  If it has,
                a third read will be correct since the count value will definitely have latched by then. */
-               first_read = counter->read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index));
-               second_read = counter->read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index));
+               first_read = counter_dev->read_register(counter_dev, counter, NITIO_Gi_SW_Save_Reg(counter->counter_index));
+               second_read = counter_dev->read_register(counter_dev, counter, NITIO_Gi_SW_Save_Reg(counter->counter_index));
                if(first_read != second_read)
-                       correct_read = counter->read_register(counter, NITIO_Gi_SW_Save_Reg(counter->counter_index));
+                       correct_read = counter_dev->read_register(counter_dev, counter, NITIO_Gi_SW_Save_Reg(counter->counter_index));
                else
                        correct_read = first_read;
                data[0] = correct_read;
                return 0;
                break;
        case 1:
-               data[0] = counter->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)];
+               data[0] = counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)];
                break;
        case 2:
-               data[0] = counter->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)];
+               data[0] = counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)];
                break;
        };
        return 0;
 }
 
-static unsigned ni_tio_next_load_register(struct ni_gpct *counter)
+static unsigned ni_tio_next_load_register(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter)
 {
-       const unsigned bits = counter->read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index));
+       const unsigned bits = counter_dev->read_register(counter_dev, counter, NITIO_Gxx_Status_Reg(counter->counter_index));
 
        if(bits & Gi_Next_Load_Source_Bit(counter->counter_index))
        {
@@ -1995,7 +2043,7 @@ static unsigned ni_tio_next_load_register(struct ni_gpct *counter)
        }
 }
 
-int ni_tio_winsn(struct ni_gpct *counter,
+int ni_tio_winsn(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter,
        comedi_insn *insn,
        lsampl_t * data)
 {
@@ -2009,19 +2057,19 @@ int ni_tio_winsn(struct ni_gpct *counter,
        case 0:
                /* Unsafe if counter is armed.  Should probably check status and return -EBUSY if armed. */
                /* Don't disturb load source select, just use whichever load register is already selected. */
-               load_reg = ni_tio_next_load_register(counter);
-               counter->write_register(counter, data[0], load_reg);
-               counter->write_register(counter, counter->regs[command_reg] | Gi_Load_Bit, command_reg);
+               load_reg = ni_tio_next_load_register(counter_dev, counter);
+               counter_dev->write_register(counter_dev, counter, data[0], load_reg);
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[command_reg] | Gi_Load_Bit, command_reg);
                /* restore state of load reg to whatever the user set last set it to */
-               counter->write_register(counter, counter->regs[load_reg], load_reg);
+               counter_dev->write_register(counter_dev, counter, counter_dev->regs[load_reg], load_reg);
                break;
        case 1:
-               counter->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = data[0];
-               counter->write_register(counter, data[0], NITIO_Gi_LoadA_Reg(counter->counter_index));
+               counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = data[0];
+               counter_dev->write_register(counter_dev, counter, data[0], NITIO_Gi_LoadA_Reg(counter->counter_index));
                break;
        case 2:
-               counter->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = data[0];
-               counter->write_register(counter, data[0], NITIO_Gi_LoadB_Reg(counter->counter_index));
+               counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = data[0];
+               counter_dev->write_register(counter_dev, counter, data[0], NITIO_Gi_LoadB_Reg(counter->counter_index));
                break;
        default:
                return -EINVAL;
@@ -2030,7 +2078,7 @@ int ni_tio_winsn(struct ni_gpct *counter,
        return 0;
 }
 
-static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async)
+static int ni_tio_input_cmd(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter, comedi_async *async)
 {
        comedi_cmd *cmd = &async->cmd;
 
@@ -2039,48 +2087,63 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async)
 
        counter->mite_chan->dir = COMEDI_INPUT;
        mite_prep_dma(counter->mite_chan, 32, 32);
-       if(counter->variant == ni_gpct_variant_m_series ||
-               counter->variant == ni_gpct_variant_660x)
+       if(counter_dev->variant == ni_gpct_variant_m_series ||
+               counter_dev->variant == ni_gpct_variant_660x)
        {
-               counter->write_register(counter, Gi_DMA_Enable_Bit, NITIO_Gi_DMA_Config_Reg(counter->counter_index));
+               counter_dev->write_register(counter_dev, counter, Gi_DMA_Enable_Bit, NITIO_Gi_DMA_Config_Reg(counter->counter_index));
        }
        /*start the MITE*/
        mite_dma_arm(counter->mite_chan);
-       return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
+       return ni_tio_arm(counter_dev, counter, 1, NI_GPCT_ARM_IMMEDIATE);
 }
 
-static int ni_tio_output_cmd(struct ni_gpct *counter, comedi_async *async)
+static int ni_tio_output_cmd(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, comedi_async *async)
 {
        return 0;
 }
 
-int ni_tio_cmd(struct ni_gpct *counter, comedi_async *async)
+int ni_tio_cmd(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, comedi_async *async)
 {
        comedi_cmd *cmd = &async->cmd;
+       int retval;
 
        if(counter->mite_chan == NULL)
        {
                rt_printk("ni_tio: commands only supported with DMA.  Interrupt-driven commands not yet implemented.\n");
-               return -EIO;
-       }
-       ni_tio_reset_count_and_disarm(counter);
-       if(cmd->flags & CMDF_WRITE)
-       {
-               return ni_tio_output_cmd(counter, async);
+               retval = -EIO;
        }else
        {
-               return ni_tio_input_cmd(counter, async);
+               ni_tio_reset_count_and_disarm(counter_dev, counter);
+               if(cmd->flags & CMDF_WRITE)
+               {
+                       retval = ni_tio_output_cmd(counter_dev, counter, async);
+               }else
+               {
+                       retval = ni_tio_input_cmd(counter_dev, counter, async);
+               }
        }
+       return retval;
 }
 
-int ni_tio_cmdtest(struct ni_gpct *counter)
+int ni_tio_cmdtest(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter)
 {
        return 0;
 }
 
-int ni_tio_cancel(struct ni_gpct *counter)
+int ni_tio_cancel(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter)
 {
-       if(counter->mite_chan == NULL) return 0;
+       if(counter->mite_chan == NULL)
+       {
+               return 0;
+       }
+       ni_tio_arm(counter_dev, counter, 0, 0);
+       if(counter_dev->variant == ni_gpct_variant_m_series ||
+               counter_dev->variant == ni_gpct_variant_660x)
+       {
+               counter_dev->write_register(counter_dev, counter, 0, NITIO_Gi_DMA_Config_Reg(counter->counter_index));
+       }
        mite_dma_disarm(counter->mite_chan);
        return 0;
 }
@@ -2092,3 +2155,5 @@ EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
 EXPORT_SYMBOL_GPL(ni_tio_cancel);
 EXPORT_SYMBOL_GPL(ni_tio_insn_config);
 EXPORT_SYMBOL_GPL(ni_tio_init_counter);
+EXPORT_SYMBOL_GPL(ni_gpct_device_construct);
+EXPORT_SYMBOL_GPL(ni_gpct_device_destroy);
index bd32398b5082a55181d74da270c3119424da4939..1f584fd430e7ebac35ba0b7433906bfb7663c1c8 100644 (file)
@@ -99,32 +99,50 @@ enum ni_gpct_variant
 };
 
 #define MAX_NUM_NITIO_REGS 0x40
+
 struct ni_gpct
 {
-       comedi_device *dev;
        unsigned counter_index;
        unsigned chip_index;
-       void (*write_register)(struct ni_gpct *this, unsigned bits, enum ni_gpct_register reg);
-       unsigned (*read_register)(struct ni_gpct *this, enum ni_gpct_register reg);
-       enum ni_gpct_variant variant;
        uint64_t clock_period_ps; /* clock period in picoseconds */
        struct mite_channel *mite_chan;
+};
+
+struct ni_gpct_device
+{
+       comedi_device *dev;
+       void (*write_register)(struct ni_gpct_device *this, const struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg);
+       unsigned (*read_register)(struct ni_gpct_device *this, const struct ni_gpct *counter, enum ni_gpct_register reg);
+       enum ni_gpct_variant variant;
+       struct ni_gpct *counters;
+       unsigned num_counters;
        unsigned regs[MAX_NUM_NITIO_REGS];
 };
 
-extern void ni_tio_init_counter(struct ni_gpct *counter);
-extern int ni_tio_rinsn(struct ni_gpct *counter,
+extern struct ni_gpct_device* ni_gpct_device_construct(comedi_device *dev,
+       void (*write_register)(struct ni_gpct_device *this, const struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg),
+       unsigned (*read_register)(struct ni_gpct_device *this, const struct ni_gpct *counter, enum ni_gpct_register reg),
+       enum ni_gpct_variant variant, unsigned num_counters);
+extern void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev);
+extern void ni_tio_init_counter(struct ni_gpct_device *counter_dev, const struct ni_gpct *counter);
+extern int ni_tio_rinsn(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter,
        comedi_insn *insn,
        lsampl_t *data);
-extern int ni_tio_insn_config(struct ni_gpct *counter,
+extern int ni_tio_insn_config(struct ni_gpct_device *counter_dev,
+       struct ni_gpct *counter,
        comedi_insn *insn,
        lsampl_t *data);
-extern int ni_tio_winsn(struct ni_gpct *counter,
+extern int ni_tio_winsn(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter,
        comedi_insn *insn,
        lsampl_t * data);
-extern int ni_tio_cmd(struct ni_gpct *counter, comedi_async *async);
-extern int ni_tio_cmdtest(struct ni_gpct *counter);
-extern int ni_tio_cancel(struct ni_gpct *counter);
+extern int ni_tio_cmd(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter, comedi_async *async);
+extern int ni_tio_cmdtest(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter);
+extern int ni_tio_cancel(struct ni_gpct_device *counter_dev,
+       const struct ni_gpct *counter);
 
 #endif /* _COMEDI_NI_TIO_H */