staging: comedi: comedi_test: make timer rate similar to scan rate
[deliverable/linux.git] / drivers / staging / comedi / drivers / comedi_test.c
index 021522882905c64bfa4504d1d0d0cd3344a526b9..9655dc333e3494c85bae485eedd14324201e0728 100644 (file)
@@ -52,6 +52,7 @@
 
 #include <linux/timer.h>
 #include <linux/ktime.h>
+#include <linux/jiffies.h>
 
 #define N_CHANS 8
 
@@ -61,15 +62,14 @@ enum waveform_state_bits {
 
 /* Data unique to this driver */
 struct waveform_private {
-       struct timer_list timer;
-       ktime_t last;   /* time last timer interrupt occurred */
-       unsigned int uvolt_amplitude;   /* waveform amplitude in microvolts */
-       unsigned long usec_period;      /* waveform period in microseconds */
-       unsigned long usec_current;     /* current time (mod waveform period) */
-       unsigned long usec_remainder;   /* usec since last scan */
+       struct timer_list ai_timer;     /* timer for AI commands */
+       u64 ai_last_scan_time;          /* time of last AI scan in usec */
+       unsigned int wf_amplitude;      /* waveform amplitude in microvolts */
+       unsigned int wf_period;         /* waveform period in microseconds */
+       unsigned int wf_current;        /* current time in waveform period */
        unsigned long state_bits;
-       unsigned int scan_period;       /* scan period in usec */
-       unsigned int convert_period;    /* conversion period in usec */
+       unsigned int ai_scan_period;    /* AI scan period in usec */
+       unsigned int ai_convert_period; /* AI conversion period in usec */
        unsigned int ao_loopbacks[N_CHANS];
 };
 
@@ -83,7 +83,7 @@ static const struct comedi_lrange waveform_ai_ranges = {
 
 static unsigned short fake_sawtooth(struct comedi_device *dev,
                                    unsigned int range_index,
-                                   unsigned long current_time)
+                                   unsigned int current_time)
 {
        struct waveform_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
@@ -94,12 +94,12 @@ static unsigned short fake_sawtooth(struct comedi_device *dev,
        u64 binary_amplitude;
 
        binary_amplitude = s->maxdata;
-       binary_amplitude *= devpriv->uvolt_amplitude;
+       binary_amplitude *= devpriv->wf_amplitude;
        do_div(binary_amplitude, krange->max - krange->min);
 
        value = current_time;
        value *= binary_amplitude * 2;
-       do_div(value, devpriv->usec_period);
+       do_div(value, devpriv->wf_period);
        value += offset;
        /* get rid of sawtooth's dc offset and clamp value */
        if (value < binary_amplitude) {
@@ -115,7 +115,7 @@ static unsigned short fake_sawtooth(struct comedi_device *dev,
 
 static unsigned short fake_squarewave(struct comedi_device *dev,
                                      unsigned int range_index,
-                                     unsigned long current_time)
+                                     unsigned int current_time)
 {
        struct waveform_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
@@ -125,11 +125,11 @@ static unsigned short fake_squarewave(struct comedi_device *dev,
            &s->range_table->range[range_index];
 
        value = s->maxdata;
-       value *= devpriv->uvolt_amplitude;
+       value *= devpriv->wf_amplitude;
        do_div(value, krange->max - krange->min);
 
        /* get one of two values for square-wave and clamp */
-       if (current_time < devpriv->usec_period / 2) {
+       if (current_time < devpriv->wf_period / 2) {
                if (offset < value)
                        value = 0;              /* negative saturation */
                else
@@ -145,7 +145,7 @@ static unsigned short fake_squarewave(struct comedi_device *dev,
 
 static unsigned short fake_flatline(struct comedi_device *dev,
                                    unsigned int range_index,
-                                   unsigned long current_time)
+                                   unsigned int current_time)
 {
        return dev->read_subdev->maxdata / 2;
 }
@@ -153,7 +153,7 @@ static unsigned short fake_flatline(struct comedi_device *dev,
 /* generates a different waveform depending on what channel is read */
 static unsigned short fake_waveform(struct comedi_device *dev,
                                    unsigned int channel, unsigned int range,
-                                   unsigned long current_time)
+                                   unsigned int current_time)
 {
        enum {
                SAWTOOTH_CHAN,
@@ -184,49 +184,44 @@ static void waveform_ai_interrupt(unsigned long arg)
        struct comedi_async *async = s->async;
        struct comedi_cmd *cmd = &async->cmd;
        unsigned int i, j;
-       /* all times in microsec */
        unsigned long elapsed_time;
        unsigned int num_scans;
-       ktime_t now;
 
        /* check command is still active */
        if (!test_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits))
                return;
 
-       now = ktime_get();
-
-       elapsed_time = ktime_to_us(ktime_sub(now, devpriv->last));
-       devpriv->last = now;
-       num_scans =
-           (devpriv->usec_remainder + elapsed_time) / devpriv->scan_period;
-       devpriv->usec_remainder =
-           (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period;
+       elapsed_time = ktime_to_us(ktime_get()) - devpriv->ai_last_scan_time;
+       num_scans = elapsed_time / devpriv->ai_scan_period;
 
        num_scans = comedi_nscans_left(s, num_scans);
        for (i = 0; i < num_scans; i++) {
-               unsigned long scan_remain_period = devpriv->scan_period;
+               unsigned int scan_remain_period = devpriv->ai_scan_period;
 
                for (j = 0; j < cmd->chanlist_len; j++) {
                        unsigned short sample;
 
-                       if (devpriv->usec_current >= devpriv->usec_period)
-                               devpriv->usec_current %= devpriv->usec_period;
+                       if (devpriv->wf_current >= devpriv->wf_period)
+                               devpriv->wf_current %= devpriv->wf_period;
                        sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]),
                                               CR_RANGE(cmd->chanlist[j]),
-                                              devpriv->usec_current);
+                                              devpriv->wf_current);
                        comedi_buf_write_samples(s, &sample, 1);
-                       devpriv->usec_current += devpriv->convert_period;
-                       scan_remain_period -= devpriv->convert_period;
+                       devpriv->wf_current += devpriv->ai_convert_period;
+                       scan_remain_period -= devpriv->ai_convert_period;
                }
-               devpriv->usec_current += scan_remain_period;
+               devpriv->wf_current += scan_remain_period;
+               devpriv->ai_last_scan_time += devpriv->ai_scan_period;
        }
-       if (devpriv->usec_current >= devpriv->usec_period)
-               devpriv->usec_current %= devpriv->usec_period;
+       if (devpriv->wf_current >= devpriv->wf_period)
+               devpriv->wf_current %= devpriv->wf_period;
 
-       if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
+       if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) {
                async->events |= COMEDI_CB_EOA;
-       else
-               mod_timer(&devpriv->timer, jiffies + 1);
+       } else {
+               mod_timer(&devpriv->ai_timer,
+                         jiffies + usecs_to_jiffies(devpriv->ai_scan_period));
+       }
 
        comedi_handle_events(dev, s);
 }
@@ -337,6 +332,7 @@ static int waveform_ai_cmd(struct comedi_device *dev,
 {
        struct waveform_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
+       u64 wf_current;
 
        if (cmd->flags & CMDF_PRIORITY) {
                dev_err(dev->class_dev,
@@ -345,28 +341,30 @@ static int waveform_ai_cmd(struct comedi_device *dev,
        }
 
        if (cmd->convert_src == TRIG_NOW)
-               devpriv->convert_period = 0;
+               devpriv->ai_convert_period = 0;
        else            /* cmd->convert_src == TRIG_TIMER */
-               devpriv->convert_period = cmd->convert_arg / NSEC_PER_USEC;
+               devpriv->ai_convert_period = cmd->convert_arg / NSEC_PER_USEC;
 
        if (cmd->scan_begin_src == TRIG_FOLLOW) {
-               devpriv->scan_period = devpriv->convert_period *
-                                      cmd->scan_end_arg;
+               devpriv->ai_scan_period = devpriv->ai_convert_period *
+                                         cmd->scan_end_arg;
        } else {        /* cmd->scan_begin_src == TRIG_TIMER */
-               devpriv->scan_period = cmd->scan_begin_arg / NSEC_PER_USEC;
+               devpriv->ai_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC;
        }
 
-       devpriv->last = ktime_get();
-       devpriv->usec_current =
-               ((u32)ktime_to_us(devpriv->last)) % devpriv->usec_period;
-       devpriv->usec_remainder = 0;
+       devpriv->ai_last_scan_time = ktime_to_us(ktime_get());
+       /* Determine time within waveform period. */
+       wf_current = devpriv->ai_last_scan_time;
+       devpriv->wf_current = do_div(wf_current, devpriv->wf_period);
+
+       devpriv->ai_timer.expires =
+               jiffies + usecs_to_jiffies(devpriv->ai_scan_period);
 
-       devpriv->timer.expires = jiffies + 1;
        /* mark command as active */
        smp_mb__before_atomic();
        set_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits);
        smp_mb__after_atomic();
-       add_timer(&devpriv->timer);
+       add_timer(&devpriv->ai_timer);
        return 0;
 }
 
@@ -379,7 +377,7 @@ static int waveform_ai_cancel(struct comedi_device *dev,
        clear_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits);
        smp_mb__after_atomic();
        /* cannot call del_timer_sync() as may be called from timer routine */
-       del_timer(&devpriv->timer);
+       del_timer(&devpriv->ai_timer);
        return 0;
 }
 
@@ -429,8 +427,8 @@ static int waveform_attach(struct comedi_device *dev,
        if (period <= 0)
                period = 100000;        /* 0.1 sec */
 
-       devpriv->uvolt_amplitude = amplitude;
-       devpriv->usec_period = period;
+       devpriv->wf_amplitude = amplitude;
+       devpriv->wf_period = period;
 
        ret = comedi_alloc_subdevices(dev, 2);
        if (ret)
@@ -464,13 +462,13 @@ static int waveform_attach(struct comedi_device *dev,
        for (i = 0; i < s->n_chan; i++)
                devpriv->ao_loopbacks[i] = s->maxdata / 2;
 
-       setup_timer(&devpriv->timer, waveform_ai_interrupt,
+       setup_timer(&devpriv->ai_timer, waveform_ai_interrupt,
                    (unsigned long)dev);
 
        dev_info(dev->class_dev,
-                "%s: %i microvolt, %li microsecond waveform attached\n",
+                "%s: %u microvolt, %u microsecond waveform attached\n",
                 dev->board_name,
-                devpriv->uvolt_amplitude, devpriv->usec_period);
+                devpriv->wf_amplitude, devpriv->wf_period);
 
        return 0;
 }
@@ -480,7 +478,7 @@ static void waveform_detach(struct comedi_device *dev)
        struct waveform_private *devpriv = dev->private;
 
        if (devpriv)
-               del_timer_sync(&devpriv->timer);
+               del_timer_sync(&devpriv->ai_timer);
 }
 
 static struct comedi_driver waveform_driver = {
This page took 0.047034 seconds and 5 git commands to generate.