Merge branch 'omap-serial' of git://git.linaro.org/people/rmk/linux-arm
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / ni_660x.c
index df2f3b0bab4843201bb37c0cbda38f7395e56041..26baf9c96fff74b0338cd53a848377927009712c 100644 (file)
@@ -419,16 +419,6 @@ static const struct ni_660x_board ni_660x_boards[] = {
 #define NI_660X_MAX_NUM_CHIPS 2
 #define NI_660X_MAX_NUM_COUNTERS (NI_660X_MAX_NUM_CHIPS * counters_per_chip)
 
-static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c60)},
-       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1310)},
-       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1360)},
-       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2cc0)},
-       {0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_660x_pci_table);
-
 struct ni_660x_private {
        struct mite_struct *mite;
        struct ni_gpct_device *counter_dev;
@@ -443,78 +433,11 @@ struct ni_660x_private {
        unsigned short pfi_output_selects[NUM_PFI_CHANNELS];
 };
 
-static inline struct ni_660x_private *private(struct comedi_device *dev)
-{
-       return dev->private;
-}
-
-/* initialized in ni_660x_attach_pci() */
-static inline const struct ni_660x_board *board(struct comedi_device *dev)
-{
-       return dev->board_ptr;
-}
-
-static int ni_660x_attach_pci(struct comedi_device *dev,
-                             struct pci_dev *pcidev);
-static void ni_660x_detach(struct comedi_device *dev);
-static void init_tio_chip(struct comedi_device *dev, int chipset);
-static void ni_660x_select_pfi_output(struct comedi_device *dev,
-                                     unsigned pfi_channel,
-                                     unsigned output_select);
-
-static struct comedi_driver ni_660x_driver = {
-       .driver_name = "ni_660x",
-       .module = THIS_MODULE,
-       .attach_pci = ni_660x_attach_pci,
-       .detach = ni_660x_detach,
-};
-
-static int __devinit ni_660x_pci_probe(struct pci_dev *dev,
-                                      const struct pci_device_id *ent)
-{
-       return comedi_pci_auto_config(dev, &ni_660x_driver);
-}
-
-static void __devexit ni_660x_pci_remove(struct pci_dev *dev)
-{
-       comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver ni_660x_pci_driver = {
-       .name = "ni_660x",
-       .id_table = ni_660x_pci_table,
-       .probe = ni_660x_pci_probe,
-       .remove = __devexit_p(ni_660x_pci_remove)
-};
-module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver);
-
-static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan,
-                                  unsigned source);
-
-/* Possible instructions for a GPCT */
-static int ni_660x_GPCT_rinsn(struct comedi_device *dev,
-                             struct comedi_subdevice *s,
-                             struct comedi_insn *insn, unsigned int *data);
-static int ni_660x_GPCT_insn_config(struct comedi_device *dev,
-                                   struct comedi_subdevice *s,
-                                   struct comedi_insn *insn,
-                                   unsigned int *data);
-static int ni_660x_GPCT_winsn(struct comedi_device *dev,
-                             struct comedi_subdevice *s,
-                             struct comedi_insn *insn, unsigned int *data);
-
-/* Possible instructions for Digital IO */
-static int ni_660x_dio_insn_config(struct comedi_device *dev,
-                                  struct comedi_subdevice *s,
-                                  struct comedi_insn *insn,
-                                  unsigned int *data);
-static int ni_660x_dio_insn_bits(struct comedi_device *dev,
-                                struct comedi_subdevice *s,
-                                struct comedi_insn *insn, unsigned int *data);
-
 static inline unsigned ni_660x_num_counters(struct comedi_device *dev)
 {
-       return board(dev)->n_chips * counters_per_chip;
+       const struct ni_660x_board *board = comedi_board(dev);
+
+       return board->n_chips * counters_per_chip;
 }
 
 static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
@@ -737,8 +660,9 @@ static inline void ni_660x_write_register(struct comedi_device *dev,
                                          unsigned chip_index, unsigned bits,
                                          enum NI_660x_Register reg)
 {
+       struct ni_660x_private *devpriv = dev->private;
        void __iomem *write_address =
-           private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
+           devpriv->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
            registerData[reg].offset;
 
        switch (registerData[reg].size) {
@@ -758,8 +682,9 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev,
                                             unsigned chip_index,
                                             enum NI_660x_Register reg)
 {
+       struct ni_660x_private *devpriv = dev->private;
        void __iomem *read_address =
-           private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
+           devpriv->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
            registerData[reg].offset;
 
        switch (registerData[reg].size) {
@@ -806,54 +731,56 @@ static inline void ni_660x_set_dma_channel(struct comedi_device *dev,
                                           unsigned mite_channel,
                                           struct ni_gpct *counter)
 {
+       struct ni_660x_private *devpriv = dev->private;
        unsigned long flags;
-       spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags);
-       private(dev)->dma_configuration_soft_copies[counter->chip_index] &=
+
+       spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+       devpriv->dma_configuration_soft_copies[counter->chip_index] &=
            ~dma_select_mask(mite_channel);
-       private(dev)->dma_configuration_soft_copies[counter->chip_index] |=
+       devpriv->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
+                              devpriv->dma_configuration_soft_copies
                               [counter->chip_index] |
                               dma_reset_bit(mite_channel), DMAConfigRegister);
        mmiowb();
-       spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags);
+       spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
 }
 
 static inline void ni_660x_unset_dma_channel(struct comedi_device *dev,
                                             unsigned mite_channel,
                                             struct ni_gpct *counter)
 {
+       struct ni_660x_private *devpriv = dev->private;
        unsigned long flags;
-       spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags);
-       private(dev)->dma_configuration_soft_copies[counter->chip_index] &=
+
+       spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+       devpriv->dma_configuration_soft_copies[counter->chip_index] &=
            ~dma_select_mask(mite_channel);
-       private(dev)->dma_configuration_soft_copies[counter->chip_index] |=
+       devpriv->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
+                              devpriv->dma_configuration_soft_copies
                               [counter->chip_index], DMAConfigRegister);
        mmiowb();
-       spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags);
+       spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
 }
 
 static int ni_660x_request_mite_channel(struct comedi_device *dev,
                                        struct ni_gpct *counter,
                                        enum comedi_io_direction direction)
 {
+       struct ni_660x_private *devpriv = dev->private;
        unsigned long flags;
        struct mite_channel *mite_chan;
 
-       spin_lock_irqsave(&private(dev)->mite_channel_lock, flags);
+       spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
        BUG_ON(counter->mite_chan);
-       mite_chan =
-           mite_request_channel(private(dev)->mite, mite_ring(private(dev),
-                                                              counter));
+       mite_chan = mite_request_channel(devpriv->mite,
+                                        mite_ring(devpriv, counter));
        if (mite_chan == NULL) {
-               spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags);
+               spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
                comedi_error(dev,
                             "failed to reserve mite dma channel for counter.");
                return -EBUSY;
@@ -861,16 +788,17 @@ static int ni_660x_request_mite_channel(struct comedi_device *dev,
        mite_chan->dir = direction;
        ni_tio_set_mite_channel(counter, mite_chan);
        ni_660x_set_dma_channel(dev, mite_chan->channel, counter);
-       spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags);
+       spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
        return 0;
 }
 
 static void ni_660x_release_mite_channel(struct comedi_device *dev,
                                         struct ni_gpct *counter)
 {
+       struct ni_660x_private *devpriv = dev->private;
        unsigned long flags;
 
-       spin_lock_irqsave(&private(dev)->mite_channel_lock, flags);
+       spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
        if (counter->mite_chan) {
                struct mite_channel *mite_chan = counter->mite_chan;
 
@@ -878,7 +806,7 @@ static void ni_660x_release_mite_channel(struct comedi_device *dev,
                ni_tio_set_mite_channel(counter, NULL);
                mite_release_channel(mite_chan);
        }
-       spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags);
+       spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 }
 
 static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -947,6 +875,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev,
 static irqreturn_t ni_660x_interrupt(int irq, void *d)
 {
        struct comedi_device *dev = d;
+       struct ni_660x_private *devpriv = dev->private;
        struct comedi_subdevice *s;
        unsigned i;
        unsigned long flags;
@@ -954,24 +883,26 @@ static irqreturn_t ni_660x_interrupt(int irq, void *d)
        if (dev->attached == 0)
                return IRQ_NONE;
        /* lock to avoid race with comedi_poll */
-       spin_lock_irqsave(&private(dev)->interrupt_lock, flags);
+       spin_lock_irqsave(&devpriv->interrupt_lock, flags);
        smp_mb();
        for (i = 0; i < ni_660x_num_counters(dev); ++i) {
                s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)];
                ni_660x_handle_gpct_interrupt(dev, s);
        }
-       spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags);
+       spin_unlock_irqrestore(&devpriv->interrupt_lock, flags);
        return IRQ_HANDLED;
 }
 
 static int ni_660x_input_poll(struct comedi_device *dev,
                              struct comedi_subdevice *s)
 {
+       struct ni_660x_private *devpriv = dev->private;
        unsigned long flags;
+
        /* lock to avoid race with comedi_poll */
-       spin_lock_irqsave(&private(dev)->interrupt_lock, flags);
+       spin_lock_irqsave(&devpriv->interrupt_lock, flags);
        mite_sync_input_dma(subdev_to_counter(s)->mite_chan, s->async);
-       spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags);
+       spin_unlock_irqrestore(&devpriv->interrupt_lock, flags);
        return comedi_buf_read_n_available(s->async);
 }
 
@@ -979,9 +910,10 @@ static int ni_660x_buf_change(struct comedi_device *dev,
                              struct comedi_subdevice *s,
                              unsigned long new_size)
 {
+       struct ni_660x_private *devpriv = dev->private;
        int ret;
 
-       ret = mite_buf_change(mite_ring(private(dev), subdev_to_counter(s)),
+       ret = mite_buf_change(mite_ring(devpriv, subdev_to_counter(s)),
                              s->async);
        if (ret < 0)
                return ret;
@@ -991,32 +923,35 @@ static int ni_660x_buf_change(struct comedi_device *dev,
 
 static int ni_660x_allocate_private(struct comedi_device *dev)
 {
-       int retval;
+       struct ni_660x_private *devpriv;
        unsigned i;
 
-       retval = alloc_private(dev, sizeof(struct ni_660x_private));
-       if (retval < 0)
-               return retval;
+       devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+       if (!devpriv)
+               return -ENOMEM;
+       dev->private = devpriv;
 
-       spin_lock_init(&private(dev)->mite_channel_lock);
-       spin_lock_init(&private(dev)->interrupt_lock);
-       spin_lock_init(&private(dev)->soft_reg_copy_lock);
+       spin_lock_init(&devpriv->mite_channel_lock);
+       spin_lock_init(&devpriv->interrupt_lock);
+       spin_lock_init(&devpriv->soft_reg_copy_lock);
        for (i = 0; i < NUM_PFI_CHANNELS; ++i)
-               private(dev)->pfi_output_selects[i] = pfi_output_select_counter;
+               devpriv->pfi_output_selects[i] = pfi_output_select_counter;
 
        return 0;
 }
 
 static int ni_660x_alloc_mite_rings(struct comedi_device *dev)
 {
+       const struct ni_660x_board *board = comedi_board(dev);
+       struct ni_660x_private *devpriv = dev->private;
        unsigned i;
        unsigned j;
 
-       for (i = 0; i < board(dev)->n_chips; ++i) {
+       for (i = 0; i < board->n_chips; ++i) {
                for (j = 0; j < counters_per_chip; ++j) {
-                       private(dev)->mite_rings[i][j] =
-                           mite_alloc_ring(private(dev)->mite);
-                       if (private(dev)->mite_rings[i][j] == NULL)
+                       devpriv->mite_rings[i][j] =
+                           mite_alloc_ring(devpriv->mite);
+                       if (devpriv->mite_rings[i][j] == NULL)
                                return -ENOMEM;
                }
        }
@@ -1025,12 +960,14 @@ static int ni_660x_alloc_mite_rings(struct comedi_device *dev)
 
 static void ni_660x_free_mite_rings(struct comedi_device *dev)
 {
+       const struct ni_660x_board *board = comedi_board(dev);
+       struct ni_660x_private *devpriv = dev->private;
        unsigned i;
        unsigned j;
 
-       for (i = 0; i < board(dev)->n_chips; ++i) {
+       for (i = 0; i < board->n_chips; ++i) {
                for (j = 0; j < counters_per_chip; ++j)
-                       mite_free_ring(private(dev)->mite_rings[i][j]);
+                       mite_free_ring(devpriv->mite_rings[i][j]);
        }
 }
 
@@ -1048,145 +985,6 @@ ni_660x_find_boardinfo(struct pci_dev *pcidev)
        return NULL;
 }
 
-static int __devinit ni_660x_attach_pci(struct comedi_device *dev,
-                                       struct pci_dev *pcidev)
-{
-       struct comedi_subdevice *s;
-       int ret;
-       unsigned i;
-       unsigned global_interrupt_config_bits;
-
-       ret = ni_660x_allocate_private(dev);
-       if (ret < 0)
-               return ret;
-       dev->board_ptr = ni_660x_find_boardinfo(pcidev);
-       if (!dev->board_ptr)
-               return -ENODEV;
-       private(dev)->mite = mite_alloc(pcidev);
-       if (!private(dev)->mite)
-               return -ENOMEM;
-
-       dev->board_name = board(dev)->name;
-
-       ret = mite_setup2(private(dev)->mite, 1);
-       if (ret < 0) {
-               dev_warn(dev->class_dev, "error setting up mite\n");
-               return ret;
-       }
-       comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev);
-       ret = ni_660x_alloc_mite_rings(dev);
-       if (ret < 0)
-               return ret;
-
-       ret = comedi_alloc_subdevices(dev, 2 + NI_660X_MAX_NUM_COUNTERS);
-       if (ret)
-               return ret;
-
-       s = &dev->subdevices[0];
-       /* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */
-       s->type = COMEDI_SUBD_UNUSED;
-
-       s = &dev->subdevices[NI_660X_DIO_SUBDEV];
-       /* DIGITAL I/O SUBDEVICE */
-       s->type = COMEDI_SUBD_DIO;
-       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-       s->n_chan = NUM_PFI_CHANNELS;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = ni_660x_dio_insn_bits;
-       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 */
-       ni_660x_write_register(dev, 0, 0, STCDIOControl);
-
-       private(dev)->counter_dev = ni_gpct_device_construct(dev,
-                                                    &ni_gpct_write_register,
-                                                    &ni_gpct_read_register,
-                                                    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[NI_660X_GPCT_SUBDEV(i)];
-               if (i < ni_660x_num_counters(dev)) {
-                       s->type = COMEDI_SUBD_COUNTER;
-                       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->do_cmd = &ni_660x_cmd;
-                       s->len_chanlist = 1;
-                       s->do_cmdtest = &ni_660x_cmdtest;
-                       s->cancel = &ni_660x_cancel;
-                       s->poll = &ni_660x_input_poll;
-                       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 / counters_per_chip;
-                       private(dev)->counter_dev->counters[i].counter_index =
-                           i % counters_per_chip;
-               } else {
-                       s->type = COMEDI_SUBD_UNUSED;
-               }
-       }
-       for (i = 0; i < board(dev)->n_chips; ++i)
-               init_tio_chip(dev, i);
-
-       for (i = 0; i < ni_660x_num_counters(dev); ++i)
-               ni_tio_init_counter(&private(dev)->counter_dev->counters[i]);
-
-       for (i = 0; i < NUM_PFI_CHANNELS; ++i) {
-               if (i < min_counter_pfi_chan)
-                       ni_660x_set_pfi_routing(dev, i, pfi_output_select_do);
-               else
-                       ni_660x_set_pfi_routing(dev, i,
-                                               pfi_output_select_counter);
-               ni_660x_select_pfi_output(dev, i, pfi_output_select_high_Z);
-       }
-       /* to be safe, set counterswap bits on tio chips after all the counter
-          outputs have been set to high impedance mode */
-       for (i = 0; i < board(dev)->n_chips; ++i)
-               set_tio_counterswap(dev, i);
-
-       ret = request_irq(mite_irq(private(dev)->mite), ni_660x_interrupt,
-                         IRQF_SHARED, "ni_660x", dev);
-       if (ret < 0) {
-               dev_warn(dev->class_dev, " irq not available\n");
-               return ret;
-       }
-       dev->irq = mite_irq(private(dev)->mite);
-       global_interrupt_config_bits = Global_Int_Enable_Bit;
-       if (board(dev)->n_chips > 1)
-               global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
-       ni_660x_write_register(dev, 0, global_interrupt_config_bits,
-                              GlobalInterruptConfigRegister);
-       dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name);
-       return 0;
-}
-
-static void ni_660x_detach(struct comedi_device *dev)
-{
-       if (dev->irq)
-               free_irq(dev->irq, dev);
-       if (dev->private) {
-               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);
-                       mite_free(private(dev)->mite);
-               }
-       }
-}
-
 static int
 ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
                   struct comedi_insn *insn, unsigned int *data)
@@ -1196,17 +994,17 @@ ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 
 static void init_tio_chip(struct comedi_device *dev, int chipset)
 {
+       struct ni_660x_private *devpriv = dev->private;
        unsigned i;
 
        /*  init dma configuration register */
-       private(dev)->dma_configuration_soft_copies[chipset] = 0;
+       devpriv->dma_configuration_soft_copies[chipset] = 0;
        for (i = 0; i < MAX_DMA_CHANNEL; ++i) {
-               private(dev)->dma_configuration_soft_copies[chipset] |=
+               devpriv->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],
+                              devpriv->dma_configuration_soft_copies[chipset],
                               DMAConfigRegister);
        for (i = 0; i < NUM_PFI_CHANNELS; ++i)
                ni_660x_write_register(dev, chipset, 0, IOConfigReg(i));
@@ -1251,6 +1049,7 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev,
                                      unsigned pfi_channel,
                                      unsigned output_select)
 {
+       const struct ni_660x_board *board = comedi_board(dev);
        static const unsigned counter_4_7_first_pfi = 8;
        static const unsigned counter_4_7_last_pfi = 23;
        unsigned active_chipset = 0;
@@ -1258,7 +1057,7 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev,
        unsigned active_bits;
        unsigned idle_bits;
 
-       if (board(dev)->n_chips > 1) {
+       if (board->n_chips > 1) {
                if (output_select == pfi_output_select_counter &&
                    pfi_channel >= counter_4_7_first_pfi &&
                    pfi_channel <= counter_4_7_last_pfi) {
@@ -1294,6 +1093,8 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev,
 static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan,
                                   unsigned source)
 {
+       struct ni_660x_private *devpriv = dev->private;
+
        if (source > num_pfi_output_selects)
                return -EINVAL;
        if (source == pfi_output_select_high_Z)
@@ -1305,76 +1106,249 @@ static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan,
                if (source == pfi_output_select_do)
                        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))
+       devpriv->pfi_output_selects[chan] = source;
+       if (devpriv->pfi_direction_bits & (((uint64_t) 1) << chan))
                ni_660x_select_pfi_output(dev, chan,
-                                         private(dev)->
-                                         pfi_output_selects[chan]);
+                                         devpriv->pfi_output_selects[chan]);
        return 0;
 }
 
-static unsigned ni_660x_get_pfi_routing(struct comedi_device *dev,
-                                       unsigned chan)
-{
-       BUG_ON(chan >= NUM_PFI_CHANNELS);
-       return private(dev)->pfi_output_selects[chan];
-}
-
-static void ni660x_config_filter(struct comedi_device *dev,
-                                unsigned pfi_channel,
-                                enum ni_gpct_filter_select filter)
-{
-       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);
-       ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel));
-}
-
 static int ni_660x_dio_insn_config(struct comedi_device *dev,
                                   struct comedi_subdevice *s,
-                                  struct comedi_insn *insn, unsigned int *data)
+                                  struct comedi_insn *insn,
+                                  unsigned int *data)
 {
-       int chan = CR_CHAN(insn->chanspec);
-
-       /* The input or output configuration of each digital line is
-        * configured by a special insn_config instruction.  chanspec
-        * contains the channel to be changed, and data[0] contains the
-        * value COMEDI_INPUT or COMEDI_OUTPUT. */
+       struct ni_660x_private *devpriv = dev->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       uint64_t bit = 1ULL << chan;
+       unsigned int val;
+       int ret;
 
        switch (data[0]) {
        case INSN_CONFIG_DIO_OUTPUT:
-               private(dev)->pfi_direction_bits |= ((uint64_t) 1) << chan;
+               devpriv->pfi_direction_bits |= bit;
                ni_660x_select_pfi_output(dev, chan,
-                                         private(dev)->
-                                         pfi_output_selects[chan]);
+                                         devpriv->pfi_output_selects[chan]);
                break;
+
        case INSN_CONFIG_DIO_INPUT:
-               private(dev)->pfi_direction_bits &= ~(((uint64_t) 1) << chan);
+               devpriv->pfi_direction_bits &= ~bit;
                ni_660x_select_pfi_output(dev, chan, pfi_output_select_high_Z);
                break;
+
        case INSN_CONFIG_DIO_QUERY:
-               data[1] =
-                   (private(dev)->pfi_direction_bits &
-                    (((uint64_t) 1) << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-               return 0;
+               data[1] = (devpriv->pfi_direction_bits & bit) ? COMEDI_OUTPUT
+                                                             : COMEDI_INPUT;
+               break;
+
        case INSN_CONFIG_SET_ROUTING:
-               return ni_660x_set_pfi_routing(dev, chan, data[1]);
+               ret = ni_660x_set_pfi_routing(dev, chan, data[1]);
+               if (ret)
+                       return ret;
                break;
+
        case INSN_CONFIG_GET_ROUTING:
-               data[1] = ni_660x_get_pfi_routing(dev, chan);
+               data[1] = devpriv->pfi_output_selects[chan];
                break;
+
        case INSN_CONFIG_FILTER:
-               ni660x_config_filter(dev, chan, data[1]);
+               val = ni_660x_read_register(dev, 0, IOConfigReg(chan));
+               val &= ~pfi_input_select_mask(chan);
+               val |= pfi_input_select_bits(chan, data[1]);
+               ni_660x_write_register(dev, 0, val, IOConfigReg(chan));
                break;
+
        default:
                return -EINVAL;
-               break;
        }
+
+       return insn->n;
+}
+
+static int ni_660x_auto_attach(struct comedi_device *dev,
+                                        unsigned long context_unused)
+{
+       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+       const struct ni_660x_board *board;
+       struct ni_660x_private *devpriv;
+       struct comedi_subdevice *s;
+       int ret;
+       unsigned i;
+       unsigned global_interrupt_config_bits;
+
+       ret = ni_660x_allocate_private(dev);
+       if (ret < 0)
+               return ret;
+       devpriv = dev->private;
+
+       dev->board_ptr = ni_660x_find_boardinfo(pcidev);
+       if (!dev->board_ptr)
+               return -ENODEV;
+       board = comedi_board(dev);
+
+       devpriv->mite = mite_alloc(pcidev);
+       if (!devpriv->mite)
+               return -ENOMEM;
+
+       dev->board_name = board->name;
+
+       ret = mite_setup2(devpriv->mite, 1);
+       if (ret < 0) {
+               dev_warn(dev->class_dev, "error setting up mite\n");
+               return ret;
+       }
+
+       ret = ni_660x_alloc_mite_rings(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = comedi_alloc_subdevices(dev, 2 + NI_660X_MAX_NUM_COUNTERS);
+       if (ret)
+               return ret;
+
+       s = &dev->subdevices[0];
+       /* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */
+       s->type = COMEDI_SUBD_UNUSED;
+
+       s = &dev->subdevices[NI_660X_DIO_SUBDEV];
+       /* DIGITAL I/O SUBDEVICE */
+       s->type = COMEDI_SUBD_DIO;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+       s->n_chan = NUM_PFI_CHANNELS;
+       s->maxdata = 1;
+       s->range_table = &range_digital;
+       s->insn_bits = ni_660x_dio_insn_bits;
+       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 */
+       ni_660x_write_register(dev, 0, 0, STCDIOControl);
+
+       devpriv->counter_dev = ni_gpct_device_construct(dev,
+                                                    &ni_gpct_write_register,
+                                                    &ni_gpct_read_register,
+                                                    ni_gpct_variant_660x,
+                                                    ni_660x_num_counters
+                                                    (dev));
+       if (devpriv->counter_dev == NULL)
+               return -ENOMEM;
+       for (i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) {
+               s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)];
+               if (i < ni_660x_num_counters(dev)) {
+                       s->type = COMEDI_SUBD_COUNTER;
+                       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->do_cmd = &ni_660x_cmd;
+                       s->len_chanlist = 1;
+                       s->do_cmdtest = &ni_660x_cmdtest;
+                       s->cancel = &ni_660x_cancel;
+                       s->poll = &ni_660x_input_poll;
+                       s->async_dma_dir = DMA_BIDIRECTIONAL;
+                       s->buf_change = &ni_660x_buf_change;
+                       s->private = &devpriv->counter_dev->counters[i];
+
+                       devpriv->counter_dev->counters[i].chip_index =
+                           i / counters_per_chip;
+                       devpriv->counter_dev->counters[i].counter_index =
+                           i % counters_per_chip;
+               } else {
+                       s->type = COMEDI_SUBD_UNUSED;
+               }
+       }
+       for (i = 0; i < board->n_chips; ++i)
+               init_tio_chip(dev, i);
+
+       for (i = 0; i < ni_660x_num_counters(dev); ++i)
+               ni_tio_init_counter(&devpriv->counter_dev->counters[i]);
+
+       for (i = 0; i < NUM_PFI_CHANNELS; ++i) {
+               if (i < min_counter_pfi_chan)
+                       ni_660x_set_pfi_routing(dev, i, pfi_output_select_do);
+               else
+                       ni_660x_set_pfi_routing(dev, i,
+                                               pfi_output_select_counter);
+               ni_660x_select_pfi_output(dev, i, pfi_output_select_high_Z);
+       }
+       /* to be safe, set counterswap bits on tio chips after all the counter
+          outputs have been set to high impedance mode */
+       for (i = 0; i < board->n_chips; ++i)
+               set_tio_counterswap(dev, i);
+
+       ret = request_irq(mite_irq(devpriv->mite), ni_660x_interrupt,
+                         IRQF_SHARED, "ni_660x", dev);
+       if (ret < 0) {
+               dev_warn(dev->class_dev, " irq not available\n");
+               return ret;
+       }
+       dev->irq = mite_irq(devpriv->mite);
+       global_interrupt_config_bits = Global_Int_Enable_Bit;
+       if (board->n_chips > 1)
+               global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
+       ni_660x_write_register(dev, 0, global_interrupt_config_bits,
+                              GlobalInterruptConfigRegister);
+       dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name);
        return 0;
 }
 
+static void ni_660x_detach(struct comedi_device *dev)
+{
+       struct ni_660x_private *devpriv = dev->private;
+
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+       if (devpriv) {
+               if (devpriv->counter_dev)
+                       ni_gpct_device_destroy(devpriv->counter_dev);
+               if (devpriv->mite) {
+                       ni_660x_free_mite_rings(dev);
+                       mite_unsetup(devpriv->mite);
+                       mite_free(devpriv->mite);
+               }
+       }
+}
+
+static struct comedi_driver ni_660x_driver = {
+       .driver_name    = "ni_660x",
+       .module         = THIS_MODULE,
+       .auto_attach    = ni_660x_auto_attach,
+       .detach         = ni_660x_detach,
+};
+
+static int ni_660x_pci_probe(struct pci_dev *dev,
+                                      const struct pci_device_id *ent)
+{
+       return comedi_pci_auto_config(dev, &ni_660x_driver);
+}
+
+static void ni_660x_pci_remove(struct pci_dev *dev)
+{
+       comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c60)},
+       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1310)},
+       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1360)},
+       {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2cc0)},
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, ni_660x_pci_table);
+
+static struct pci_driver ni_660x_pci_driver = {
+       .name           = "ni_660x",
+       .id_table       = ni_660x_pci_table,
+       .probe          = ni_660x_pci_probe,
+       .remove         = ni_660x_pci_remove,
+};
+module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver);
+
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");