aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/ni_660x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/ni_660x.c')
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c586
1 files changed, 280 insertions, 306 deletions
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index df2f3b0bab48..26baf9c96fff 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -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");