The DAQ700Card has an 8254 counter/timer that provides 3 counters.
Counter 0 controls the onboard data acquisition timing, and all three
counters are available for general-purpose timing functions.

Add a subdevice to allow the user to use the counters.

Signed-off-by: H Hartley Sweeten <hswee...@visionengravers.com>
Cc: Ian Abbott <abbo...@mev.co.uk>
Cc: Greg Kroah-Hartman <gr...@linuxfoundation.org>
---
 drivers/staging/comedi/comedi.h             |   9 ++
 drivers/staging/comedi/drivers/ni_daq_700.c | 125 +++++++++++++++++++++++++++-
 2 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index dbaeba7..c722748 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -987,4 +987,13 @@ enum ke_counter_clock_source {
        KE_CLK_EXT      /* external clock on pin 21 of D-Sub */
 };
 
+/*
+ * Values for setting the counter 1 clock source with INSN_CONFIG_SET_CLOCK_SRC
+ * for the counter subdevice on the NI PCMCIA DAQCard-700 (ni_daq_700 driver).
+ */
+enum ni_daq700_counter_clock_source {
+       DAQ700_CLK_EXT,         /* external CLK1 signal (default) */
+       DAQ700_CLK_1MHZ,        /* internal 1MHz */
+};
+
 #endif /* _COMEDI_H */
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c 
b/drivers/staging/comedi/drivers/ni_daq_700.c
index e1e7ba7..4ff3556 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -589,6 +589,112 @@ static int daq700_ai_cmdtest(struct comedi_device *dev,
        return 0;
 }
 
+static int daq700_counter_insn_read(struct comedi_device *dev,
+                                   struct comedi_subdevice *s,
+                                   struct comedi_insn *insn,
+                                   unsigned int *data)
+{
+       unsigned long timer_base = dev->iobase + DAQ700_TIMER_BASE;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       int i;
+
+       for (i = 0; i < insn->n; i++)
+               data[i] = i8254_read(timer_base, 0, chan);
+
+       return insn->n;
+}
+
+static int daq700_counter_insn_write(struct comedi_device *dev,
+                                    struct comedi_subdevice *s,
+                                    struct comedi_insn *insn,
+                                    unsigned int *data)
+{
+       unsigned long timer_base = dev->iobase + DAQ700_TIMER_BASE;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+
+       /* only write the final value to the counter */
+       if (insn->n)
+               i8254_write(timer_base, 0, chan, data[insn->n - 1]);
+
+       return insn->n;
+}
+
+static int daq700_counter_insn_config(struct comedi_device *dev,
+                                     struct comedi_subdevice *s,
+                                     struct comedi_insn *insn,
+                                     unsigned int *data)
+{
+       struct daq700_private *devpriv = dev->private;
+       unsigned long timer_base = dev->iobase + DAQ700_TIMER_BASE;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+
+       switch (data[0]) {
+       case INSN_CONFIG_SET_CLOCK_SRC:
+               switch (chan) {
+               case 1:
+                       switch (data[1]) {
+                       case DAQ700_CLK_EXT:
+                               /* CLK1 signal from I/O connector */
+                               devpriv->cmd3 &= ~DAQ700_CMD3_CLK1SRC;
+                               break;
+                       case DAQ700_CLK_1MHZ:
+                               /* CLK1 from internal 1MHz */
+                               devpriv->cmd3 |= DAQ700_CMD3_CLK1SRC;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       outb(devpriv->cmd3, dev->iobase + DAQ700_CMD3_REG);
+                       break;
+               default:
+                       /*
+                        * The clock source cannot be changed for all
+                        * other channels.
+                        */
+                       return -EINVAL;
+               }
+               break;
+       case INSN_CONFIG_GET_CLOCK_SRC:
+               switch (chan) {
+               case 0:
+                       /* counter 0 is connected to the 1MHz internal clock */
+                       data[1] = DAQ700_CLK_1MHZ;
+                       data[2] = I8254_OSC_BASE_1MHZ;
+                       break;
+               case 1:
+                       /*
+                        * Counter 1 can use the 1MHz internal clock or an
+                        * external clock.
+                        */
+                       if (devpriv->cmd3 & DAQ700_CMD3_CLK1SRC) {
+                               data[1] = DAQ700_CLK_1MHZ;
+                               data[2] = I8254_OSC_BASE_1MHZ;
+                       } else {
+                               data[1] = DAQ700_CLK_EXT;
+                               data[2] = 0;    /* unknown */
+                       }
+                       break;
+               case 2:
+                       /* counter 2 uses an external clock */
+                       data[1] = DAQ700_CLK_EXT;
+                       data[2] = 0;    /* unknown */
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case INSN_CONFIG_SET_COUNTER_MODE:
+               i8254_set_mode(timer_base, 0, chan, data[1]);
+               break;
+       case INSN_CONFIG_8254_READ_STATUS:
+               data[1] = i8254_status(timer_base, 0, chan);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return insn->n;
+}
+
 /*
  * Data acquisition is enabled.
  * The counter 0 output is high.
@@ -640,7 +746,7 @@ static int daq700_auto_attach(struct comedi_device *dev,
        if (ret == 0)
                dev->irq = link->irq;
 
-       ret = comedi_alloc_subdevices(dev, 2);
+       ret = comedi_alloc_subdevices(dev, 3);
        if (ret)
                return ret;
 
@@ -672,6 +778,23 @@ static int daq700_auto_attach(struct comedi_device *dev,
                s->cancel       = daq700_ai_cancel;
        }
 
+       /*
+        * Counter/Timer subdevice
+        *
+        * The 8254 has three counters - 0, 1, and 2. Counter 0 controls
+        * the onboard data acquisition timing, and all three counters
+        * are available for general-purpose timing functions.
+        */
+       s = &dev->subdevices[2];
+       s->type         = COMEDI_SUBD_COUNTER;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+       s->n_chan       = 3;
+       s->maxdata      = 0xffff;
+       s->range_table  = &range_unknown;
+       s->insn_config  = daq700_counter_insn_config;
+       s->insn_write   = daq700_counter_insn_write;
+       s->insn_read    = daq700_counter_insn_read;
+
        return 0;
 }
 
-- 
1.9.3

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to