Moved some interrupt enable/disable and interrupt handling
authorFrank Mori Hess <fmhess@speakeasy.net>
Wed, 15 Aug 2007 21:22:49 +0000 (21:22 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Wed, 15 Aug 2007 21:22:49 +0000 (21:22 +0000)
stuff from client drivers into ni_tio.c.
ni_stc.h:
Added some stuff for correlated digital output waveforms
that I missed in earlier commit.
ni_660x.c:
Added beginnings of support for buffered input counting (untested,
definitely doesn't work yet due to empty interrupt handler).
Added INSN_CONFIG_SET/GET_ROUTING support,
to allow switching of output signals between
counter outputs and static digital output.  Fixed channel mix-ups
on input/output selection for static dio.  Fixed static digital
output to work on full 32 bits.  Replaced some preprocessor macros
with inline functions.

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 d1d8c17545d1ef379f2a171594d6a39f53e89ae4..02fdd9108f5351dfe114ed60218c3b08ffcea941 100644 (file)
@@ -49,6 +49,8 @@ Things to do:
 
 #define CTRS_PER_CHIP 4 // The number of counters per ni-tio chip
 #define NUM_PFI_CHANNELS 40
+// really there are only up to 3 dma channels, but the register layout allows for 4
+#define MAX_DMA_CHANNEL 4
 
 /* See Register-Level Programmer Manual page 3.1 */
 typedef enum
@@ -59,14 +61,18 @@ typedef enum
        G1StatusRegister,
        G01StatusRegister,
        G0CommandRegister,
+       STCDIOParallelInput,
        G1CommandRegister,
        G0HWSaveRegister,
        G1HWSaveRegister,
+       STCDIOOutput,
+       STCDIOControl,
        G0SWSaveRegister,
        G1SWSaveRegister,
        G0ModeRegister,
        G01JointStatus1Register,
        G1ModeRegister,
+       STCDIOSerialInput,
        G0LoadARegister,
        G01JointStatus2Register,
        G0LoadBRegister,
@@ -121,8 +127,12 @@ typedef enum
        G2DMAStatusRegister,
        G3DMAConfigRegister,
        G3DMAStatusRegister,
+       DIO32Input,
+       DIO32Output,
        ClockConfigRegister,
-       DMAConfigRegister,      // XXX will need to use this according to mite channel used
+       GlobalInterruptStatusRegister,
+       DMAConfigRegister,
+       GlobalInterruptConfigRegister,
        IOConfigReg0_1,
        IOConfigReg2_3,
        IOConfigReg4_5,
@@ -143,12 +153,6 @@ typedef enum
        IOConfigReg34_35,
        IOConfigReg36_37,
        IOConfigReg38_39,
-       STCDIOParallelInput,
-       STCDIOOutput,
-       STCDIOControl,
-       STCDIOSerialInput,
-       DIO32Input,
-       DIO32Output,
        NumRegisters,
 } NI_660x_Register;
 
@@ -173,6 +177,14 @@ enum ni_660x_register_direction
        NI_660x_READ_WRITE
 };
 
+enum ni_660x_pfi_output_select
+{
+       pfi_output_select_high_Z = 0,
+       pfi_output_select_counter = 1,
+       pfi_output_select_do = 2,
+       num_pfi_output_selects
+};
+
 typedef struct
 {
        const char *name; // Register Name
@@ -190,14 +202,18 @@ static const NI_660xRegisterData registerData[NumRegisters] =
        {"G1 Status Register", 0x006, NI_660x_READ, DATA_2B},
        {"G01 Status Register ", 0x008, NI_660x_READ, DATA_2B},
        {"G0 Command Register", 0x00C, NI_660x_WRITE, DATA_2B},
+       {"STD DIO Parallel Input", 0x00E, NI_660x_READ, DATA_2B},
        {"G1 Command Register", 0x00E, NI_660x_WRITE, DATA_2B},
        {"G0 HW Save Register", 0x010, NI_660x_READ, DATA_4B},
        {"G1 HW Save Register", 0x014, NI_660x_READ, DATA_4B},
+       {"STD DIO Output", 0x014, NI_660x_WRITE, DATA_2B},
+       {"STD DIO Control", 0x016, NI_660x_WRITE, DATA_2B},
        {"G0 SW Save Register", 0x018, NI_660x_READ, DATA_4B},
        {"G1 SW Save Register", 0x01C, NI_660x_READ, DATA_4B},
        {"G0 Mode Register", 0x034, NI_660x_WRITE, DATA_2B},
        {"G01 Joint Status 1 Register", 0x036, NI_660x_READ, DATA_2B},
        {"G1 Mode Register", 0x036, NI_660x_WRITE, DATA_2B},
+       {"STD DIO Serial Input", 0x038, NI_660x_READ, DATA_2B},
        {"G0 Load A Register", 0x038, NI_660x_WRITE, DATA_4B},
        {"G01 Joint Status 2 Register", 0x03A, NI_660x_READ, DATA_2B},
        {"G0 Load B Register", 0x03C, NI_660x_WRITE, DATA_4B},
@@ -252,9 +268,13 @@ static const NI_660xRegisterData registerData[NumRegisters] =
        {"G2 DMA Status Register", 0x1B8, NI_660x_READ, DATA_2B},
        {"G3 DMA Config Register", 0x1BA, NI_660x_WRITE, DATA_2B},
        {"G3 DMA Status Register", 0x1BA, NI_660x_READ, DATA_2B},
+       {"32 bit Digital Input", 0x414, NI_660x_READ, DATA_4B},
+       {"32 bit Digital Output", 0x510, NI_660x_WRITE, DATA_4B},
        {"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
+       {"Global Interrupt Status Register", 0x754, NI_660x_READ, DATA_4B},
+       {"DMA Configuration Register", 0x76C, NI_660x_WRITE, DATA_4B},
+       {"Global Interrupt Config Register", 0x770, NI_660x_WRITE, DATA_4B},
+       {"IO Config Register 0-1", 0x77C, NI_660x_READ_WRITE, DATA_2B},
        {"IO Config Register 2-3", 0x77E, NI_660x_READ_WRITE, DATA_2B},
        {"IO Config Register 4-5", 0x780, NI_660x_READ_WRITE, DATA_2B},
        {"IO Config Register 6-7", 0x782, NI_660x_READ_WRITE, DATA_2B},
@@ -273,36 +293,62 @@ static const NI_660xRegisterData registerData[NumRegisters] =
        {"IO Config Register 32-33", 0x79C, NI_660x_READ_WRITE, DATA_2B},
        {"IO Config Register 34-35", 0x79E, NI_660x_READ_WRITE, DATA_2B},
        {"IO Config Register 36-37", 0x7A0, NI_660x_READ_WRITE, DATA_2B},
-       {"IO Config Register 38-39", 0x7A2, NI_660x_READ_WRITE, DATA_2B},
-       {"STD DIO Parallel Input", 0x00E, NI_660x_READ, DATA_2B},
-       {"STD DIO Output", 0x014, NI_660x_WRITE, DATA_2B},
-       {"STD DIO Control", 0x016, NI_660x_WRITE, DATA_2B},
-       {"STD DIO Serial Input", 0x038, NI_660x_READ, DATA_2B},
-       {"32 bit Digital Input", 0x414, NI_660x_READ, DATA_4B},
-       {"32 bit Digital Output", 0x414, NI_660x_WRITE, DATA_4B}
+       {"IO Config Register 38-39", 0x7A2, NI_660x_READ_WRITE, DATA_2B}
 };
 
-#define GateSelectPin38                0x1<<8 // Take internal time-based 20
-
 // kind of ENABLE for the second counter
-#define CounterSwap             0x1<<21
+enum clock_config_register_bits
+{
+       CounterSwap = 0x1 << 21
+};
 
 // ioconfigreg
+static inline unsigned ioconfig_bitshift(unsigned pfi_channel)
+{
+       if(pfi_channel % 2) return 0;
+       else return 8;
+}
 static inline unsigned pfi_output_select_mask(unsigned pfi_channel)
 {
-       return 0x3 << (8 * (pfi_channel % 2));
+       return 0x3 << ioconfig_bitshift(pfi_channel);
 }
 static inline unsigned pfi_output_select_bits(unsigned pfi_channel, unsigned output_select)
 {
-       return (output_select & 0x3) << (8 * (pfi_channel % 2));
+       return (output_select & 0x3) << ioconfig_bitshift(pfi_channel);
 }
 static inline unsigned pfi_input_select_mask(unsigned pfi_channel)
 {
-       return 0x7 << (4 + 8 * (pfi_channel % 2));
+       return 0x7 << (4 + ioconfig_bitshift(pfi_channel));
 }
 static inline unsigned pfi_input_select_bits(unsigned pfi_channel, unsigned input_select)
 {
-       return (input_select & 0x7) << (4 + 8 * (pfi_channel % 2));
+       return (input_select & 0x7) << (4 + ioconfig_bitshift(pfi_channel));
+}
+
+// dma configuration register bits
+static inline unsigned dma_select_mask(unsigned dma_channel)
+{
+       BUG_ON(dma_channel >= MAX_DMA_CHANNEL);
+       return 0x1f << (8 * dma_channel);
+}
+enum dma_selection
+{
+       dma_selection_none = 0x1f,
+};
+static inline unsigned dma_selection_counter(unsigned counter_index)
+{
+       BUG_ON(counter_index >= CTRS_PER_CHIP);
+       return counter_index;
+}
+static inline unsigned dma_select_bits(unsigned dma_channel, unsigned selection)
+{
+       BUG_ON(dma_channel >= MAX_DMA_CHANNEL);
+       return (selection << (8 * dma_channel)) & dma_select_mask(dma_channel);
+}
+static inline unsigned dma_reset_bit(unsigned dma_channel)
+{
+       BUG_ON(dma_channel >= MAX_DMA_CHANNEL);
+       return 0x80 << (8 * dma_channel);
 }
 
 // Offset of the GPCT chips from the base-adress of the card
@@ -314,8 +360,7 @@ typedef struct
 {
        unsigned short dev_id; /* `lspci` will show you this */
        const char *name;
-       int n_ctrs; /* total number of counters */
-       int cnt_bits; /* number of bits in each counter */
+       unsigned n_chips; /* total number of TIO chips */
 } ni_660x_board;
 
 static const ni_660x_board ni_660x_boards[] =
@@ -323,17 +368,16 @@ static const ni_660x_board ni_660x_boards[] =
        {
                dev_id       : 0x2c60,
                name         : "PCI-6601",
-               n_ctrs       : 1*CTRS_PER_CHIP,
-               cnt_bits     : 32,
+               n_chips       : 1,
        },
        {
                dev_id       : 0x1310,
                name         : "PCI-6602",
-               n_ctrs       : 2*CTRS_PER_CHIP,
-               cnt_bits     : 32,
+               n_chips       : 2,
        },
 };
-#define NI_660X_MAX_NUM_COUNTERS 8
+#define NI_660X_MAX_NUM_CHIPS 2
+#define NI_660X_MAX_NUM_COUNTERS (NI_660X_MAX_NUM_CHIPS * CTRS_PER_CHIP)
 
 static struct pci_device_id ni_660x_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_NATINST, 0x2c60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
@@ -342,23 +386,34 @@ static struct pci_device_id ni_660x_pci_table[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(pci, ni_660x_pci_table);
 
-#define thisboard ((const ni_660x_board *)dev->board_ptr)
-/* initialized in ni_660x_find_device() */
-
 typedef struct
 {
        struct mite_struct *mite;
-       int boardtype;
        struct ni_gpct_device *counter_dev;
        uint64_t pfi_direction_bits;
+       struct mite_dma_descriptor_ring *mite_rings[NI_660X_MAX_NUM_CHIPS][CTRS_PER_CHIP];
+       spinlock_t mite_channel_lock;
+       unsigned dma_configuration_soft_copies[NI_660X_MAX_NUM_CHIPS];
+       spinlock_t soft_reg_copy_lock;
+       unsigned short pfi_output_selects[NUM_PFI_CHANNELS];
 }ni_660x_private;
 
-#define devpriv ((ni_660x_private *)dev->private)
+static inline ni_660x_private* private(comedi_device *dev)
+{
+       return dev->private;
+}
+/* initialized in ni_660x_find_device() */
+static inline const ni_660x_board* board(comedi_device *dev)
+{
+       return dev->board_ptr;
+}
+
 #define n_ni_660x_boards (sizeof(ni_660x_boards)/sizeof(ni_660x_boards[0]))
 
 static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it);
 static int ni_660x_detach(comedi_device *dev);
 static void init_tio_chip(comedi_device *dev, int chipset);
+static void ni_660x_select_pfi_output(comedi_device *dev, unsigned pfi_channel, unsigned output_select);
 
 static comedi_driver driver_ni_660x=
 {
@@ -386,13 +441,6 @@ static int ni_660x_GPCT_winsn(comedi_device *dev,
                              comedi_insn *insn,
                              lsampl_t * data);
 
-// NYI
-#if 0
-static int ni_660x_GPCT_cmdtest(comedi_device *dev,comedi_subdevice *s,
-                               comedi_cmd *cmd);
-static int ni_660x_GPCT_cmd(comedi_device *dev,comedi_subdevice *s);
-#endif
-
 /* Possible instructions for Digital IO */
 static int ni_660x_dio_insn_config(comedi_device *dev,
                                   comedi_subdevice *s,
@@ -403,20 +451,10 @@ static int ni_660x_dio_insn_bits(comedi_device *dev,
                                 comedi_insn *insn,
                                 lsampl_t *data);
 
-#if 0
-static int ni_660x_GPCT_cmdtest(comedi_device *dev,comedi_subdevice *s,
-                               comedi_cmd *cmd)
-{
-       DPRINTK("NI_660X: COMMANDS not implemented yet for GPCT\n");
-       return -EINVAL;
-}
-
-static int ni_660x_GPCT_cmd(comedi_device *dev,comedi_subdevice *s)
+static inline unsigned ni_660x_num_counters(comedi_device *dev)
 {
-       DPRINTK("NI_660X: COMMANDS not implemented yet for GPCT\n");
-       return -EINVAL;
+       return board(dev)->n_chips * CTRS_PER_CHIP;
 }
-#endif
 
 static NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
 {
@@ -615,6 +653,18 @@ static NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
        case NITIO_G3_Status_Reg:
                ni_660x_register = G0StatusRegister;
                break;
+       case NITIO_G0_Interrupt_Enable_Reg:
+               ni_660x_register = G0InterruptEnable;
+               break;
+       case NITIO_G1_Interrupt_Enable_Reg:
+               ni_660x_register = G1InterruptEnable;
+               break;
+       case NITIO_G2_Interrupt_Enable_Reg:
+               ni_660x_register = G2InterruptEnable;
+               break;
+       case NITIO_G3_Interrupt_Enable_Reg:
+               ni_660x_register = G3InterruptEnable;
+               break;
        default:
                rt_printk("%s: unhandled register 0x%x in switch.\n", __FUNCTION__, reg);
                BUG();
@@ -624,13 +674,12 @@ 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 inline void ni_660x_write_register(comedi_device *dev, unsigned chip_index, unsigned bits, NI_660x_Register reg)
 {
-       NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
-       comedi_device *dev = counter->counter_dev->dev;
-       void * const write_address = devpriv->mite->daq_io_addr + GPCT_OFFSET[counter->chip_index] + registerData[ni_660x_register].offset;
+       void * const write_address = private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
+               registerData[reg].offset;
 
-       switch(registerData[ni_660x_register].size)
+       switch(registerData[reg].size)
        {
        case DATA_2B:
                writew(bits, write_address);
@@ -639,19 +688,17 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum
                writel(bits, write_address);
                break;
        default:
-               rt_printk("%s: %s: bug! unhandled case = 0x%x in switch.\n", __FILE__, __FUNCTION__, reg);
+               rt_printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", __FILE__, __FUNCTION__, reg);
                BUG();
                break;
        }
 }
 
-static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg)
+static inline unsigned ni_660x_read_register(comedi_device *dev, unsigned chip_index, NI_660x_Register reg)
 {
-       NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
-       comedi_device *dev = counter->counter_dev->dev;
-       void * const read_address = devpriv->mite->daq_io_addr + GPCT_OFFSET[counter->chip_index] + registerData[ni_660x_register].offset;
+       void * const read_address = private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + registerData[reg].offset;
 
-       switch(registerData[ni_660x_register].size)
+       switch(registerData[reg].size)
        {
        case DATA_2B:
                return readw(read_address);
@@ -660,13 +707,197 @@ static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_regi
                return readl(read_address);
                break;
        default:
-               rt_printk("%s: %s: bug! unhandled case = 0x%x in switch.\n", __FILE__, __FUNCTION__, reg);
+               rt_printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", __FILE__, __FUNCTION__, reg);
                BUG();
                break;
        }
        return 0;
 }
 
+static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
+{
+       comedi_device *dev = counter->counter_dev->dev;
+       NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
+       ni_660x_write_register(dev, counter->chip_index, bits, ni_660x_register);
+}
+
+static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg)
+{
+       comedi_device *dev = counter->counter_dev->dev;
+       NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
+       return ni_660x_read_register(dev, counter->chip_index, ni_660x_register);
+}
+
+static inline struct mite_dma_descriptor_ring* mite_ring(ni_660x_private *priv, struct ni_gpct *counter)
+{
+       return priv->mite_rings[counter->chip_index][counter->counter_index];
+}
+
+static inline void ni_660x_set_dma_channel(comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter)
+{
+       unsigned long flags;
+       comedi_spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags);
+       private(dev)->dma_configuration_soft_copies[counter->chip_index] &=
+               ~dma_select_mask(mite_channel);
+       private(dev)->dma_configuration_soft_copies[counter->chip_index] |=
+               dma_select_bits(mite_channel, dma_selection_counter(counter->counter_index));
+       ni_660x_write_register(dev, counter->chip_index, private(dev)->dma_configuration_soft_copies[counter->chip_index] |
+               dma_reset_bit(mite_channel), DMAConfigRegister);
+       mmiowb();
+       comedi_spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags);
+}
+
+static inline void ni_660x_unset_dma_channel(comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter)
+{
+       unsigned long flags;
+       comedi_spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags);
+       private(dev)->dma_configuration_soft_copies[counter->chip_index] &=
+               ~dma_select_mask(mite_channel);
+       private(dev)->dma_configuration_soft_copies[counter->chip_index] |=
+               dma_select_bits(mite_channel, dma_selection_none);
+       ni_660x_write_register(dev, counter->chip_index, private(dev)->dma_configuration_soft_copies[counter->chip_index],
+               DMAConfigRegister);
+       mmiowb();
+       comedi_spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags);
+}
+
+static int ni_660x_request_mite_channel(comedi_device *dev, struct ni_gpct *counter, enum comedi_io_direction direction)
+{
+       unsigned long flags;
+       struct mite_channel *mite_chan;
+
+       comedi_spin_lock_irqsave(&private(dev)->mite_channel_lock, flags);
+       BUG_ON(counter->mite_chan);
+       mite_chan = mite_request_channel(private(dev)->mite, mite_ring(private(dev), counter));
+       if(mite_chan == NULL)
+       {
+               comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags);
+               comedi_error(dev, "failed to reserve mite dma channel for counter.");
+               return -EBUSY;
+       }
+       mite_chan->dir = direction;
+       ni_tio_set_mite_channel(counter, mite_chan);
+       ni_660x_set_dma_channel(dev, mite_chan->channel, counter);
+       comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags);
+       return 0;
+}
+
+void ni_660x_release_mite_channel(comedi_device *dev, struct ni_gpct *counter)
+{
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&private(dev)->mite_channel_lock, flags);
+       if(counter->mite_chan)
+       {
+               struct mite_channel *mite_chan = counter->mite_chan;
+
+               ni_660x_unset_dma_channel(dev, mite_chan->channel, counter);
+               ni_tio_set_mite_channel(counter, NULL);
+               mite_release_channel(mite_chan);
+       }
+       comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags);
+}
+
+static int ni_660x_cmd(comedi_device *dev, comedi_subdevice *s)
+{
+       int retval;
+
+       struct ni_gpct *counter = subdev_to_counter(s);
+//     const comedi_cmd *cmd = &s->async->cmd;
+
+       retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT);
+       if(retval)
+       {
+               comedi_error(dev, "no dma channel available for use by counter");
+               return retval;
+       }
+       ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL);
+       retval = ni_tio_cmd(counter, s->async);
+
+       return retval;
+}
+
+static int ni_660x_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd)
+{
+       struct ni_gpct *counter = subdev_to_counter(s);
+
+       return ni_tio_cmdtest(counter, cmd);
+}
+
+static int ni_660x_cancel(comedi_device *dev, comedi_subdevice *s)
+{
+       struct ni_gpct *counter = subdev_to_counter(s);
+       int retval;
+
+       retval = ni_tio_cancel(counter);
+       ni_660x_release_mite_channel(dev, counter);
+       return retval;
+}
+
+static irqreturn_t ni_660x_interrupt(int irq, void *d PT_REGS_ARG)
+{
+       return IRQ_HANDLED;
+}
+
+static int ni_660x_buf_change(comedi_device *dev, comedi_subdevice *s,
+       unsigned long new_size)
+{
+       int ret;
+
+       ret = mite_buf_change(mite_ring(private(dev), subdev_to_counter(s)), s->async);
+       if(ret < 0) return ret;
+
+       return 0;
+}
+
+static int ni_660x_allocate_private(comedi_device *dev)
+{
+       int retval;
+       unsigned i;
+
+       if((retval = alloc_private(dev, sizeof(ni_660x_private))) < 0) return retval;
+       spin_lock_init(&private(dev)->mite_channel_lock);
+       spin_lock_init(&private(dev)->soft_reg_copy_lock);
+       for(i = 0; i < NUM_PFI_CHANNELS; ++i)
+       {
+               private(dev)->pfi_output_selects[i] = pfi_output_select_counter;
+       }
+       return 0;
+}
+
+static int ni_660x_alloc_mite_rings(comedi_device *dev)
+{
+       unsigned i;
+       unsigned j;
+
+       for(i = 0; i < board(dev)->n_chips; ++i)
+       {
+               for(j = 0; j < CTRS_PER_CHIP; ++j)
+               {
+                       private(dev)->mite_rings[i][j] = mite_alloc_ring(private(dev)->mite);
+                       if(private(dev)->mite_rings[i][j] == NULL)
+                       {
+                               return -ENOMEM;
+                       }
+               }
+       }
+       return 0;
+}
+
+static void ni_660x_free_mite_rings(comedi_device *dev)
+{
+       unsigned i;
+       unsigned j;
+
+       for(i = 0; i < board(dev)->n_chips; ++i)
+       {
+               for(j = 0; j < CTRS_PER_CHIP; ++j)
+               {
+                       mite_free_ring(private(dev)->mite_rings[i][j]);
+               }
+       }
+}
+
 static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
 {
        comedi_subdevice *s;
@@ -675,19 +906,21 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
 
        printk("comedi%d: ni_660x: ",dev->minor);
 
-       if ((ret=alloc_private(dev,sizeof(ni_660x_private))) < 0) return ret;
-
+       ret = ni_660x_allocate_private(dev);
+       if(ret < 0) return ret;
        ret = ni_660x_find_device(dev, it->options[0], it->options[1]);
        if (ret<0) return ret;
 
-       ret = mite_setup(devpriv->mite);
+       dev->board_name = board(dev)->name;
+
+       ret = mite_setup(private(dev)->mite);
        if (ret < 0) {
-       printk("error setting up mite\n");
-       return ret;
+               printk("error setting up mite\n");
+               return ret;
        }
-       dev->board_name = thisboard->name;
-       /* we don't support the interrupt yet */
-       //dev->irq = mite_irq(devpriv->mite);
+       comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev);
+       ret = ni_660x_alloc_mite_rings(dev);
+       if(ret < 0) return ret;
 
        printk(" %s ", dev->board_name);
 
@@ -710,42 +943,57 @@ static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
        s->insn_config  = ni_660x_dio_insn_config;
        s->io_bits      = 0;     /* all bits default to input */
        // 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);
+       ni_660x_write_register(dev, 0, 0, STCDIOControl);
 
-       devpriv->counter_dev = ni_gpct_device_construct(dev,
+       private(dev)->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;
+               ni_gpct_variant_660x, ni_660x_num_counters(dev));
+       if(private(dev)->counter_dev == NULL) return -ENOMEM;
        for(i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i)
        {
                s = dev->subdevices + 2 + i;
-               if(i < thisboard->n_ctrs)
+               if(i < ni_660x_num_counters(dev))
                {
                        s->type = COMEDI_SUBD_COUNTER;
-                       s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
+                       s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ /* | SDF_CMD_WRITE */;
                        s->n_chan = 3;
                        s->maxdata = 0xffffffff;
                        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->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;
+                       s->do_cmd = &ni_660x_cmd;
+                       s->len_chanlist = 1;
+                       s->do_cmdtest = &ni_660x_cmdtest;
+                       s->cancel = &ni_660x_cancel;
+                       s->async_dma_dir = DMA_BIDIRECTIONAL;
+                       s->buf_change = &ni_660x_buf_change;
+                       s->private = &private(dev)->counter_dev->counters[i];
+
+                       private(dev)->counter_dev->counters[i].chip_index = i / CTRS_PER_CHIP;
+                       private(dev)->counter_dev->counters[i].counter_index = i % CTRS_PER_CHIP;
                }else
                {
                        s->type = COMEDI_SUBD_UNUSED;
                }
        }
-       for(i = 0; i < thisboard->n_ctrs / CTRS_PER_CHIP; ++i)
+       for(i = 0; i < board(dev)->n_chips; ++i)
        {
                init_tio_chip(dev, i);
        }
-       for(i = 0; i < thisboard->n_ctrs; ++i)
+       for(i = 0; i < ni_660x_num_counters(dev); ++i)
        {
-               ni_tio_init_counter(&devpriv->counter_dev->counters[i]);
+               ni_tio_init_counter(&private(dev)->counter_dev->counters[i]);
        }
-
+       for(i = 0; i < NUM_PFI_CHANNELS; ++i)
+       {
+               ni_660x_select_pfi_output(dev, i, pfi_output_select_high_Z);
+       }
+       if((ret = comedi_request_irq(mite_irq(private(dev)->mite), &ni_660x_interrupt, IRQF_SHARED, "ni_660x", dev)) < 0)
+       {
+               printk(" irq not available\n");
+               return ret;
+       }
+       dev->irq = mite_irq(private(dev)->mite);
        printk("attached\n");
        return 0;
 }
@@ -756,18 +1004,19 @@ ni_660x_detach(comedi_device *dev)
 {
        printk("comedi%d: ni_660x: remove\n",dev->minor);
 
+       /* Free irq */
+       if(dev->irq) comedi_free_irq(dev->irq, dev);
+
        if(dev->private)
        {
-               if(devpriv->counter_dev)
-                       ni_gpct_device_destroy(devpriv->counter_dev);
-               if(devpriv->mite)
-                       mite_unsetup(devpriv->mite);
+               if(private(dev)->counter_dev)
+                       ni_gpct_device_destroy(private(dev)->counter_dev);
+               if(private(dev)->mite)
+               {
+                       ni_660x_free_mite_rings(dev);
+                       mite_unsetup(private(dev)->mite);
+               }
        }
-       /* Free irq */
-
-       if(dev->irq) comedi_free_irq(dev->irq,dev);
-
-       /* Same question as with attach ... */
        return 0;
 }
 
@@ -775,30 +1024,37 @@ static int
 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(subdev_to_counter(s), insn, data);
 }
 
 static void init_tio_chip(comedi_device *dev, int chipset)
 {
+       unsigned i;
+
        /* See P. 3.5 of the Register-Level Programming manual.  The
                CounterSwap bit has to be set on the second chip, otherwise
                it will try to use the same pins as the first chip.
        */
        if(chipset)
-               writel(CounterSwap,devpriv->mite->daq_io_addr + GPCT_OFFSET[1]
-                       + registerData[ClockConfigRegister].offset);
+               ni_660x_write_register(dev, chipset, CounterSwap, ClockConfigRegister);
        else
-               writel(0,devpriv->mite->daq_io_addr + GPCT_OFFSET[0]
-                       + registerData[ClockConfigRegister].offset);
+               ni_660x_write_register(dev, chipset, 0, ClockConfigRegister);
+       // init dma configuration register
+       private(dev)->dma_configuration_soft_copies[chipset] = 0;
+       for(i = 0; i < MAX_DMA_CHANNEL; ++i)
+       {
+               private(dev)->dma_configuration_soft_copies[chipset] |=
+                       dma_select_bits(i, dma_selection_none) & dma_select_mask(i);
+       }
+       ni_660x_write_register(dev, chipset, private(dev)->dma_configuration_soft_copies[chipset],
+               DMAConfigRegister);
 }
 
 static int
 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(subdev_to_counter(s), insn, data);
 }
 
 static int ni_660x_GPCT_winsn(comedi_device *dev,
@@ -806,8 +1062,7 @@ static int ni_660x_GPCT_winsn(comedi_device *dev,
        comedi_insn *insn,
        lsampl_t * data)
 {
-       struct ni_gpct *counter = s->private;
-       return ni_tio_winsn(counter, insn, data);
+       return ni_tio_winsn(subdev_to_counter(s), insn, data);
 }
 
 static int
@@ -826,7 +1081,7 @@ ni_660x_find_device(comedi_device *dev, int bus, int slot)
                for (i=0; i<n_ni_660x_boards; i++) {
                        if (mite_device_id(mite)==ni_660x_boards[i].dev_id) {
                                dev->board_ptr=ni_660x_boards+i;
-                               devpriv->mite=mite;
+                               private(dev)->mite=mite;
                                return 0;
                        }
                }
@@ -847,43 +1102,49 @@ static int ni_660x_dio_insn_bits(comedi_device *dev,
        // Check if we have to write some bits
        if(data[0])
        {
-               /* Only the first 8 lines can be read/written.  The rest can
-               only have their input/output configuration changed (although
-               the user manual implies the first 32 channels can be used as
-               general purpose dio, the register manual doesn't tell you how
-               this can be accomplished. */
-               /*FIXME: use DIO32Input and DIO32Output registers for dio
-               to the 32 bit port */
-               if((data[0] << base_bitfield_channel) > 0xff)
-               {
-                       return -EINVAL;
-               }
                s->state &= ~(data[0] << base_bitfield_channel);
                s->state |= (data[0] & data[1]) << base_bitfield_channel;
                /* Write out the new digital output lines */
-               writew(s->state,devpriv->mite->daq_io_addr + registerData[STCDIOOutput].offset);
+               ni_660x_write_register(dev, 0, s->state, DIO32Output);
        }
        /* on return, data[1] contains the value of the digital
        * input and output lines. */
-       data[1] = (readw(devpriv->mite->daq_io_addr + registerData[STCDIOParallelInput].offset) >> base_bitfield_channel) &
-               (0xff >> base_bitfield_channel);
+       data[1] = (ni_660x_read_register(dev, 0, DIO32Input) >> base_bitfield_channel);
        return 2;
 }
 
 static void ni_660x_select_pfi_output(comedi_device *dev, unsigned pfi_channel, unsigned output_select)
 {
-       unsigned bits = readw(devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset);
+       unsigned bits = ni_660x_read_register(dev, 0, IOConfigReg(pfi_channel));
+
        bits &= ~pfi_output_select_mask(pfi_channel);
        bits |= pfi_output_select_bits(pfi_channel, output_select);
-       writew(bits, devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset);
+       ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel));
+}
+
+static int ni_660x_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
+{
+       if(source > num_pfi_output_selects) return -EINVAL;
+       BUG_ON(chan >= NUM_PFI_CHANNELS);
+
+       private(dev)->pfi_output_selects[chan] = source;
+       if(private(dev)->pfi_direction_bits & (((uint64_t)1) << chan))
+               ni_660x_select_pfi_output(dev, chan, private(dev)->pfi_output_selects[chan]);
+       return 0;
+}
+
+static unsigned ni_660x_get_pfi_routing(comedi_device *dev, unsigned chan)
+{
+       BUG_ON(chan >= NUM_PFI_CHANNELS);
+       return private(dev)->pfi_output_selects[chan];
 }
 
 static void ni660x_config_filter(comedi_device *dev, unsigned pfi_channel, enum ni_gpct_filter_select filter)
 {
-       unsigned bits = readw(devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset);
+       unsigned bits = ni_660x_read_register(dev, 0, IOConfigReg(pfi_channel));
        bits &= ~pfi_input_select_mask(pfi_channel);
        bits |= pfi_input_select_bits(pfi_channel, filter);
-       writew(bits, devpriv->mite->daq_io_addr + registerData[IOConfigReg(pfi_channel)].offset);
+       ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel));
 }
 
 static int ni_660x_dio_insn_config(comedi_device *dev,
@@ -891,7 +1152,7 @@ static int ni_660x_dio_insn_config(comedi_device *dev,
        comedi_insn *insn,
        lsampl_t *data)
 {
-       int chan=CR_CHAN(insn->chanspec);
+       int chan = CR_CHAN(insn->chanspec);
 
        /* The input or output configuration of each digital line is
        * configured by a special insn_config instruction.  chanspec
@@ -901,17 +1162,22 @@ static int ni_660x_dio_insn_config(comedi_device *dev,
        switch(data[0])
        {
        case INSN_CONFIG_DIO_OUTPUT:
-               devpriv->pfi_direction_bits |= ((uint64_t)1) << chan;
-               //FIXME: output select 1 is counter output, 2 is digital output
-               ni_660x_select_pfi_output(dev, chan, 1);
+               private(dev)->pfi_direction_bits |= ((uint64_t)1) << chan;
+               ni_660x_select_pfi_output(dev, chan, private(dev)->pfi_output_selects[chan]);
                break;
        case INSN_CONFIG_DIO_INPUT:
-               devpriv->pfi_direction_bits &= ~(((uint64_t)1) << chan);
-               ni_660x_select_pfi_output(dev, chan, 0);
+               private(dev)->pfi_direction_bits &= ~(((uint64_t)1) << chan);
+               ni_660x_select_pfi_output(dev, chan, pfi_output_select_high_Z);
                break;
        case INSN_CONFIG_DIO_QUERY:
-               data[1] = (devpriv->pfi_direction_bits & (((uint64_t)1) << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               data[1] = (private(dev)->pfi_direction_bits & (((uint64_t)1) << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
                return 0;
+       case INSN_CONFIG_SET_ROUTING:
+               return ni_660x_set_pfi_routing(dev, chan, data[1]);
+               break;
+       case INSN_CONFIG_GET_ROUTING:
+               data[1] = ni_660x_get_pfi_routing(dev, chan);
+               break;
        case INSN_CONFIG_FILTER:
                ni660x_config_filter(dev, chan, data[1]);
                break;
index 36f96ac455508839aff54cc4240b37b0d2c3779c..fdac6580f184e764f493a41e0ae7a4f77ae9ae7c 100644 (file)
@@ -347,55 +347,53 @@ static void get_last_sample_611x( comedi_device *dev );
 static void get_last_sample_6143( comedi_device *dev );
 #ifdef PCIDMA
 static int ni_ai_drain_dma(comedi_device *dev );
+static inline void ni_set_bitfield(comedi_device *dev, int reg, unsigned bit_mask, unsigned bit_values);
 
 /* DMA channel setup */
 
 // negative channel means no channel
 static inline void ni_set_ai_dma_channel(comedi_device *dev, int channel)
 {
-       unsigned long flags;
+       unsigned bitfield;
 
-       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
-       devpriv->ai_ao_select_reg &= ~AI_DMA_Select_Mask;
        if(channel >= 0)
        {
-               devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask;
+               bitfield = (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask;
+       }else
+       {
+               bitfield = 0;
        }
-       ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
-       mmiowb();
-       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+       ni_set_bitfield(dev, AI_AO_Select, AI_DMA_Select_Mask, bitfield);
 }
 
 // negative channel means no channel
 static inline void ni_set_ao_dma_channel(comedi_device *dev, int channel)
 {
-       unsigned long flags;
+       unsigned bitfield;
 
-       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
-       devpriv->ai_ao_select_reg &= ~AO_DMA_Select_Mask;
        if(channel >= 0)
        {
-               devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask;
+               bitfield = (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask;
+       }else
+       {
+               bitfield = 0;
        }
-       ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
-       mmiowb();
-       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+       ni_set_bitfield(dev, AI_AO_Select, AO_DMA_Select_Mask, bitfield);
 }
 
 // negative mite_channel means no channel
 static inline void ni_set_gpct_dma_channel(comedi_device *dev, unsigned gpct_index, int mite_channel)
 {
-       unsigned long flags;
+       unsigned bitfield;
 
-       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
-       devpriv->g0_g1_select_reg &= ~GPCT_DMA_Select_Mask(gpct_index);
        if(mite_channel >= 0)
        {
-               devpriv->g0_g1_select_reg |= GPCT_DMA_Select_Bits(gpct_index, mite_channel);
+               bitfield = GPCT_DMA_Select_Bits(gpct_index, mite_channel);
+       }else
+       {
+               bitfield = 0;
        }
-       ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
-       mmiowb();
-       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+       ni_set_bitfield(dev, G0_G1_Select, GPCT_DMA_Select_Mask(gpct_index), bitfield);
 }
 
 // negative mite_channel means no channel
@@ -542,9 +540,11 @@ void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
        comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
        if(devpriv->counter_dev->counters[gpct_index].mite_chan)
        {
+               struct mite_channel *mite_chan = devpriv->counter_dev->counters[gpct_index].mite_chan;
+
                ni_set_gpct_dma_channel(dev, gpct_index, -1);
-               mite_release_channel(devpriv->counter_dev->counters[gpct_index].mite_chan);
                ni_tio_set_mite_channel(&devpriv->counter_dev->counters[gpct_index], NULL);
+               mite_release_channel(mite_chan);
        }
        comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 #endif // PCIDMA
@@ -666,51 +666,66 @@ static inline unsigned short ni_ao_win_inw( comedi_device *dev, int addr )
        return data;
 }
 
-/* ni_set_bits( ) allows different parts of the ni_mio_common driver to
-* share registers (such as Interrupt_A_Register) without interfering with
-* each other.
-*
-* NOTE: the switch/case statements are optimized out for a constant argument
-* so this is actually quite fast---  If you must wrap another function around this
-* make it inline to avoid a large speed penalty.
-*
-* value should only be 1 or 0.
-*/
-static inline void ni_set_bits(comedi_device *dev, int reg, int bits, int value)
+static inline void ni_set_bitfield(comedi_device *dev, int reg, unsigned bit_mask, unsigned bit_values)
 {
        unsigned long flags;
 
        comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
        switch (reg){
                case Interrupt_A_Enable_Register:
-                       if(value)
-                               devpriv->int_a_enable_reg |= bits;
-                       else
-                               devpriv->int_a_enable_reg &= ~bits;
-                       devpriv->stc_writew(dev, devpriv->int_a_enable_reg,Interrupt_A_Enable_Register);
+                       devpriv->int_a_enable_reg &= ~bit_mask;
+                       devpriv->int_a_enable_reg |=  bit_values & bit_mask;
+                       devpriv->stc_writew(dev, devpriv->int_a_enable_reg, Interrupt_A_Enable_Register);
                        break;
                case Interrupt_B_Enable_Register:
-                       if(value)
-                               devpriv->int_b_enable_reg |= bits;
-                       else
-                               devpriv->int_b_enable_reg &= ~bits;
-                       devpriv->stc_writew(dev, devpriv->int_b_enable_reg,Interrupt_B_Enable_Register);
+                       devpriv->int_b_enable_reg &= ~bit_mask;
+                       devpriv->int_b_enable_reg |=  bit_values & bit_mask;
+                       devpriv->stc_writew(dev, devpriv->int_b_enable_reg, Interrupt_B_Enable_Register);
                        break;
                case IO_Bidirection_Pin_Register:
-                       if(value)
-                               devpriv->io_bidirection_pin_reg |= bits;
-                       else
-                               devpriv->io_bidirection_pin_reg &= ~bits;
-                       devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register);
+                       devpriv->io_bidirection_pin_reg &= ~bit_mask;
+                       devpriv->io_bidirection_pin_reg |=  bit_values & bit_mask;
+                       devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg, IO_Bidirection_Pin_Register);
+                       break;
+               case AI_AO_Select:
+                       devpriv->ai_ao_select_reg &= ~bit_mask;
+                       devpriv->ai_ao_select_reg |=  bit_values & bit_mask;
+                       ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+                       break;
+               case G0_G1_Select:
+                       devpriv->g0_g1_select_reg &= ~bit_mask;
+                       devpriv->g0_g1_select_reg |=  bit_values & bit_mask;
+                       ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
                        break;
                default:
-                       rt_printk("Warning ni_set_bits() called with invalid arguments\n");
-                       rt_printk("reg is %d\n",reg);
+                       rt_printk("Warning %s() called with invalid register\n", __FUNCTION__);
+                       rt_printk("reg is %d\n", reg);
                        break;
        }
+       mmiowb();
        comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags );
 }
 
+/* ni_set_bits( ) allows different parts of the ni_mio_common driver to
+* share registers (such as Interrupt_A_Register) without interfering with
+* each other.
+*
+* NOTE: the switch/case statements are optimized out for a constant argument
+* so this is actually quite fast---  If you must wrap another function around this
+* make it inline to avoid a large speed penalty.
+*
+* value should only be 1 or 0.
+*/
+static inline void ni_set_bits(comedi_device *dev, int reg, unsigned bits, unsigned value)
+{
+       unsigned bit_values;
+
+       if(value)
+               bit_values = bits;
+       else
+               bit_values = 0;
+       ni_set_bitfield(dev, reg, bits, bit_values);
+}
 
 static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG)
 {
@@ -3758,6 +3773,12 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg)
        case NITIO_G1_Status_Reg:
                stc_register = AO_Status_1_Register;
                break;
+       case NITIO_G0_Interrupt_Enable_Reg:
+               stc_register = Interrupt_A_Enable_Register;
+               break;
+       case NITIO_G1_Interrupt_Enable_Reg:
+               stc_register = Interrupt_B_Enable_Register;
+               break;
        default:
                rt_printk("%s: unhandled register 0x%x in switch.\n", __FUNCTION__, reg);
                BUG();
@@ -3773,6 +3794,9 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum
        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;
+       static const unsigned gpct_interrupt_a_enable_mask = G0_Gate_Interrupt_Enable | G0_TC_Interrupt_Enable;
+       static const unsigned gpct_interrupt_b_enable_mask = G1_Gate_Interrupt_Enable | G1_TC_Interrupt_Enable;
+
        switch(reg)
        {
        /* m-series-only registers */
@@ -3811,6 +3835,14 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum
                break;
 
        /* 16 bit registers */
+       case NITIO_G0_Interrupt_Enable_Reg:
+               BUG_ON(bits & ~gpct_interrupt_a_enable_mask);
+               ni_set_bitfield(dev, Interrupt_A_Enable_Register, gpct_interrupt_a_enable_mask, bits);
+               break;
+       case NITIO_G1_Interrupt_Enable_Reg:
+               BUG_ON(bits & ~gpct_interrupt_b_enable_mask);
+               ni_set_bitfield(dev, Interrupt_B_Enable_Register, gpct_interrupt_b_enable_mask, bits);
+               break;
        case NITIO_G01_Joint_Reset_Reg:
                BUG_ON(bits & ~gpct_joint_reset_mask);
                /* fall-through */
@@ -4650,132 +4682,12 @@ static int ni_gpct_insn_write(comedi_device *dev, comedi_subdevice *s,
        return ni_tio_winsn(counter, insn, data);
 }
 
-static inline unsigned Gi_Interrupt_Enable_Register(unsigned counter_index)
-{
-       unsigned reg;
-
-       switch(counter_index)
-       {
-       case 0:
-               reg = Interrupt_A_Enable_Register;
-               break;
-       case 1:
-               reg = Interrupt_B_Enable_Register;
-               break;
-       default:
-               BUG();
-               return 0;
-               break;
-       }
-       return reg;
-}
-
-static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index)
-{
-       unsigned bit;
-
-       switch(counter_index)
-       {
-       case 0:
-               bit = G0_Gate_Interrupt_Enable;
-               break;
-       case 1:
-               bit = G1_Gate_Interrupt_Enable;
-               break;
-       default:
-               BUG();
-               return 0;
-               break;
-       }
-       return bit;
-}
-
-static inline unsigned Gi_Interrupt_Ack_Register(unsigned counter_index)
-{
-       unsigned reg;
-
-       switch(counter_index)
-       {
-       case 0:
-               reg = Interrupt_A_Ack_Register;
-               break;
-       case 1:
-               reg = Interrupt_B_Ack_Register;
-               break;
-       default:
-               BUG();
-               return 0;
-               break;
-       }
-       return reg;
-}
-
-static inline unsigned Gi_Gate_Interrupt_Ack_Bit(unsigned counter_index)
-{
-       unsigned bit;
-
-       switch(counter_index)
-       {
-       case 0:
-               bit = G0_Gate_Interrupt_Ack;
-               break;
-       case 1:
-               bit = G1_Gate_Interrupt_Ack;
-               break;
-       default:
-               BUG();
-               return 0;
-               break;
-       }
-       return bit;
-}
-
-static inline unsigned Gi_Gate_Error_Confirm_Bit(unsigned counter_index)
-{
-       unsigned bit;
-
-       switch(counter_index)
-       {
-       case 0:
-               bit = G0_Gate_Error_Confirm;
-               break;
-       case 1:
-               bit = G1_Gate_Error_Confirm;
-               break;
-       default:
-               BUG();
-               return 0;
-               break;
-       }
-       return bit;
-}
-
-static inline unsigned Gi_TC_Error_Confirm_Bit(unsigned counter_index)
-{
-       unsigned bit;
-
-       switch(counter_index)
-       {
-       case 0:
-               bit = G0_TC_Error_Confirm;
-               break;
-       case 1:
-               bit = G1_TC_Error_Confirm;
-               break;
-       default:
-               BUG();
-               return 0;
-               break;
-       }
-       return bit;
-}
-
 static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
 {
        int retval;
 #ifdef PCIDMA
        struct ni_gpct *counter = s->private;
-       const comedi_cmd *cmd = &s->async->cmd;
+//     const comedi_cmd *cmd = &s->async->cmd;
 
        retval = ni_request_gpct_mite_channel(dev, counter->counter_index, COMEDI_INPUT);
        if(retval)
@@ -4783,15 +4695,7 @@ static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
                comedi_error(dev, "no dma channel available for use by counter");
                return retval;
        }
-       devpriv->stc_writew(dev, Gi_Gate_Interrupt_Ack_Bit(counter->counter_index) |
-               Gi_Gate_Error_Confirm_Bit(counter->counter_index) |
-               Gi_TC_Error_Confirm_Bit(counter->counter_index),
-               Gi_Interrupt_Ack_Register(counter->counter_index));
-       if(cmd->flags & TRIG_WAKE_EOS)
-       {
-               ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index),
-                       Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 1);
-       }
+       ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL);
        ni_e_series_enable_second_irq(dev, counter->counter_index, 1);
        retval = ni_tio_cmd(counter, s->async);
 #else
@@ -4814,8 +4718,6 @@ static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s)
 
        retval = ni_tio_cancel(counter);
        ni_e_series_enable_second_irq(dev, counter->counter_index, 0);
-       ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index),
-               Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 0);
        ni_release_gpct_mite_channel(dev, counter->counter_index);
        return retval;
 }
index bf213c004c252a2054714381ddbaee5667f3fa4a..e544d8d3f11f16fe36e2d6dd1faf17f35e84d5a8 100644 (file)
@@ -1345,9 +1345,15 @@ enum CDI_Mode_Bits
 {
        CDI_Sample_Source_Select_Mask = 0x3f,
        CDI_Halt_On_Error_Bit = 0x200,
-       CDI_Polarity_Bit = 0x400,
-       CDI_FIFO_Mode_Bit = 0x800,
-       CDI_Data_Lane_Mask = 0x3000
+       CDI_Polarity_Bit = 0x400,       // sample clock on falling edge
+       CDI_FIFO_Mode_Bit = 0x800,      // set for half full mode, clear for not empty mode
+       CDI_Data_Lane_Mask = 0x3000,    // data lanes specify which dio channels map to byte or word accesses to the dio fifos
+       CDI_Data_Lane_0_15_Bits = 0x0,
+       CDI_Data_Lane_16_31_Bits = 0x1000,
+       CDI_Data_Lane_0_7_Bits = 0x0,
+       CDI_Data_Lane_8_15_Bits = 0x1000,
+       CDI_Data_Lane_16_23_Bits = 0x2000,
+       CDI_Data_Lane_24_31_Bits = 0x3000
 };
 
 enum CDO_Mode_Bits
@@ -1355,9 +1361,25 @@ enum CDO_Mode_Bits
        CDO_Sample_Source_Select_Mask = 0x3f,
        CDO_Retransmit_Bit = 0x100,
        CDO_Halt_On_Error_Bit = 0x200,
-       CDO_Polarity_Bit = 0x400,
-       CDO_FIFO_Mode_Bit = 0x800,
-       CDO_Data_Lane_Mask = 0x3000
+       CDO_Polarity_Bit = 0x400,       // sample clock on falling edge
+       CDO_FIFO_Mode_Bit = 0x800,      // set for half full mode, clear for not full mode
+       CDO_Data_Lane_Mask = 0x3000, // data lanes specify which dio channels map to byte or word accesses to the dio fifos
+       CDO_Data_Lane_0_15_Bits = 0x0,
+       CDO_Data_Lane_16_31_Bits = 0x1000,
+       CDO_Data_Lane_0_7_Bits = 0x0,
+       CDO_Data_Lane_8_15_Bits = 0x1000,
+       CDO_Data_Lane_16_23_Bits = 0x2000,
+       CDO_Data_Lane_24_31_Bits = 0x3000
+};
+
+enum Interrupt_C_Enable_Bits
+{
+       Interrupt_Group_C_Enable_Bit = 0x1
+};
+
+enum Interrupt_C_Status_Bits
+{
+       Interrupt_Group_C_Status_Bit = 0x1
 };
 
 #define M_SERIES_EEPROM_SIZE 1024
@@ -1458,6 +1480,7 @@ typedef struct ni_board_struct{
        unsigned short pfi_output_select_reg[NUM_PFI_OUTPUT_SELECT_REGS]; \
        unsigned short ai_ao_select_reg; \
        unsigned short g0_g1_select_reg; \
+       unsigned short cdio_dma_select_reg; \
        \
        unsigned clock_ns; \
        unsigned clock_source; \
@@ -1475,8 +1498,10 @@ typedef struct ni_board_struct{
        struct mite_struct *mite; \
        struct mite_channel *ai_mite_chan; \
        struct mite_channel *ao_mite_chan;\
+       struct mite_channel *cdo_mite_chan;\
        struct mite_dma_descriptor_ring *ai_mite_ring; \
        struct mite_dma_descriptor_ring *ao_mite_ring; \
+       struct mite_dma_descriptor_ring *cdo_mite_ring; \
        struct mite_dma_descriptor_ring *gpct_mite_ring[NUM_GPCT];
 
 
index 0350ecb5bd246e33a5f17d7667a240b2f2c6e886..e78dede0d19392cc88cbee3dcea88a811006d6d0 100644 (file)
@@ -29,7 +29,7 @@ Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
        Klaas.Gadeyne@mech.kuleuven.ac.be,
        Frank Mori Hess <fmhess@users.sourceforge.net>
 Updated: Thu Nov 16 09:50:32 EST 2006
-Status: experimental
+Status: works
 
 This module is not used directly by end-users.  Rather, it
 is used by other drivers (for example ni_660x and ni_pcimio)
@@ -427,6 +427,29 @@ static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index)
        return 0;
 }
 
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int counter_index)
+{
+       switch(counter_index)
+       {
+       case 0:
+               return NITIO_G0_Interrupt_Enable_Reg;
+               break;
+       case 1:
+               return NITIO_G1_Interrupt_Enable_Reg;
+               break;
+       case 2:
+               return NITIO_G2_Interrupt_Enable_Reg;
+               break;
+       case 3:
+               return NITIO_G3_Interrupt_Enable_Reg;
+               break;
+       default:
+               BUG();
+               break;
+       }
+       return 0;
+}
+
 enum Gi_Auto_Increment_Reg_Bits
 {
        Gi_Auto_Increment_Mask = 0xff
@@ -871,6 +894,31 @@ enum Gi_Status_Bits
        Gi_Interrupt_Bit = 0x8000
 };
 
+enum G02_Interrupt_Enable_Bits
+{
+       G0_TC_Interrupt_Enable_Bit = 0x40,
+       G0_Gate_Interrupt_Enable_Bit = 0x100
+};
+enum G13_Interrupt_Enable_Bits
+{
+       G1_TC_Interrupt_Enable_Bit = 0x200,
+       G1_Gate_Interrupt_Enable_Bit = 0x400
+};
+static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index)
+{
+       unsigned bit;
+
+       if(counter_index % 2)
+       {
+               bit = G1_Gate_Interrupt_Enable_Bit;
+       }else
+       {
+               bit = G0_Gate_Interrupt_Enable_Bit;
+       }
+       return bit;
+}
+
+
 static const lsampl_t counter_status_mask = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING;
 
 static inline void write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
@@ -2438,10 +2486,12 @@ static int ni_tio_output_cmd(struct ni_gpct *counter, comedi_async *async)
 
 static int ni_tio_cmd_setup(struct ni_gpct *counter, comedi_async *async)
 {
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
        comedi_cmd *cmd = &async->cmd;
        int set_gate_source = 0;
        unsigned gate_source;
        int retval = 0;
+       const unsigned interrupt_enable_reg = NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index);
 
        if(cmd->scan_begin_src == TRIG_EXT)
        {
@@ -2456,6 +2506,11 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, comedi_async *async)
        {
                retval = ni_tio_set_gate_src(counter, 0, gate_source);
        }
+       if(cmd->flags & TRIG_WAKE_EOS)
+       {
+               counter_dev->regs[interrupt_enable_reg] |= Gi_Gate_Interrupt_Enable_Bit(counter->counter_index);
+               write_register(counter, counter_dev->regs[interrupt_enable_reg], interrupt_enable_reg);
+       }
        return retval;
 }
 
@@ -2593,6 +2648,8 @@ int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd *cmd)
 
 int ni_tio_cancel(struct ni_gpct *counter)
 {
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
+       const unsigned interrupt_enable_reg = NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index);
        unsigned long flags;
 
        ni_tio_arm(counter, 0, 0);
@@ -2603,6 +2660,9 @@ int ni_tio_cancel(struct ni_gpct *counter)
        }
        comedi_spin_unlock_irqrestore(&counter->lock, flags);
        ni_tio_configure_dma(counter, 0, 0);
+
+       counter_dev->regs[interrupt_enable_reg] &= ~Gi_Gate_Interrupt_Enable_Bit(counter->counter_index);
+       write_register(counter, counter_dev->regs[interrupt_enable_reg], interrupt_enable_reg);
        return 0;
 }
 
@@ -2636,7 +2696,8 @@ static int should_ack_gate(struct ni_gpct *counter)
        return retval;
 }
 
-static void acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, int *stale_data)
+void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error,
+       int *perm_stale_data, int *stale_data)
 {
        const unsigned short gxx_status = read_register(counter, NITIO_Gxx_Status_Reg(counter->counter_index));
        const unsigned short gi_status = read_register(counter, NITIO_Gi_Status_Reg(counter->counter_index));
@@ -2666,20 +2727,17 @@ static void acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, in
                        ack |= Gi_Gate_Interrupt_Ack_Bit;
        }
        if(ack) write_register(counter, ack, NITIO_Gi_Interrupt_Acknowledge_Reg(counter->counter_index));
-       if(gxx_status & Gi_Stale_Data_Bit(counter->counter_index))
-       {
-               /* If we should support interrupt transfers in addition to dma in the future,
-               then we would put a zero into the buffer instead of the (stale) counter value if
-               reload on gate is enabled. */
-//             rt_printk("%s: Gi_Stale_Data detected.\n", __FUNCTION__);
-       }
-       if(read_register(counter, NITIO_Gxx_Joint_Status2_Reg(counter->counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index))
+       if(ni_tio_get_soft_copy(counter, NITIO_Gi_Mode_Reg(counter->counter_index)) & Gi_Loading_On_Gate_Bit)
        {
-               if(ni_tio_get_soft_copy(counter, NITIO_Gi_Mode_Reg(counter->counter_index)) & Gi_Loading_On_Gate_Bit)
+               if(gxx_status & Gi_Stale_Data_Bit(counter->counter_index))
                {
-                       rt_printk("%s: Gi_Permanent_Stale_Data detected.\n", __FUNCTION__);
                        if(stale_data) *stale_data = 1;
                }
+               if(read_register(counter, NITIO_Gxx_Joint_Status2_Reg(counter->counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index))
+               {
+                       rt_printk("%s: Gi_Permanent_Stale_Data detected.\n", __FUNCTION__);
+                       if(perm_stale_data) *perm_stale_data = 1;
+               }
        }
 }
 
@@ -2689,15 +2747,15 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, comedi_subdevice *s)
        unsigned long flags;
        int gate_error;
        int tc_error;
-       int stale_data;
+       int perm_stale_data;
 
-       acknowledge_and_confirm(counter, &gate_error, &tc_error, &stale_data);
+       ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error, &perm_stale_data, NULL);
        if(gate_error)
        {
                rt_printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__);
                s->async->events |= COMEDI_CB_OVERFLOW;
        }
-       if(stale_data)
+       if(perm_stale_data)
        {
                s->async->events |= COMEDI_CB_ERROR;
        }
@@ -2750,3 +2808,4 @@ EXPORT_SYMBOL_GPL(ni_gpct_device_construct);
 EXPORT_SYMBOL_GPL(ni_gpct_device_destroy);
 EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
 EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel);
+EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm);
index 18e5803a5202874d9ac8afeeb2be0136120e753e..6e3e3ba4e5561e7c80b541077dcfd5a03dcffa5b 100644 (file)
@@ -97,6 +97,10 @@ enum ni_gpct_register
        NITIO_G1_Status_Reg,
        NITIO_G2_Status_Reg,
        NITIO_G3_Status_Reg,
+       NITIO_G0_Interrupt_Enable_Reg,
+       NITIO_G1_Interrupt_Enable_Reg,
+       NITIO_G2_Interrupt_Enable_Reg,
+       NITIO_G3_Interrupt_Enable_Reg,
        NITIO_Num_Registers,
 };
 
@@ -107,8 +111,6 @@ enum ni_gpct_variant
        ni_gpct_variant_660x
 };
 
-#define MAX_NUM_NITIO_REGS 0x40
-
 struct ni_gpct
 {
        struct ni_gpct_device *counter_dev;
@@ -127,7 +129,7 @@ struct ni_gpct_device
        enum ni_gpct_variant variant;
        struct ni_gpct *counters;
        unsigned num_counters;
-       unsigned regs[MAX_NUM_NITIO_REGS];
+       unsigned regs[NITIO_Num_Registers];
        spinlock_t regs_lock;
 };
 
@@ -151,6 +153,13 @@ extern int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd *cmd);
 extern int ni_tio_cancel(struct ni_gpct *counter);
 extern void ni_tio_handle_interrupt(struct ni_gpct *counter, comedi_subdevice *s);
 extern void ni_tio_set_mite_channel(struct ni_gpct *counter, struct mite_channel *mite_chan);
+extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error,
+       int *perm_stale_data, int *stale_data);
+
+static inline struct ni_gpct* subdev_to_counter(comedi_subdevice *s)
+{
+       return s->private;
+}
 
 #endif /* _COMEDI_NI_TIO_H */