diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index b8fd4d24b421..8c348bbf9e71 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -56,6 +56,10 @@ zero volts). #define N_CHANS 8 +enum waveform_state_bits { + WAVEFORM_AI_RUNNING = 0 +}; + /* Data unique to this driver */ struct waveform_private { struct timer_list timer; @@ -65,6 +69,7 @@ struct waveform_private { unsigned long usec_current; /* current time (mod waveform period) */ unsigned long usec_remainder; /* usec since last scan */ unsigned long ai_count; /* number of conversions remaining */ + unsigned long state_bits; unsigned int scan_period; /* scan period in usec */ unsigned int convert_period; /* conversion period in usec */ unsigned int ao_loopbacks[N_CHANS]; @@ -175,6 +180,10 @@ static void waveform_ai_interrupt(unsigned long arg) ktime_t now; bool stopping = false; + /* 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)); @@ -322,6 +331,10 @@ static int waveform_ai_cmd(struct comedi_device *dev, devpriv->usec_remainder = 0; 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); return 0; } @@ -331,7 +344,11 @@ static int waveform_ai_cancel(struct comedi_device *dev, { struct waveform_private *devpriv = dev->private; - del_timer_sync(&devpriv->timer); + /* mark command as no longer active */ + 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); return 0; } @@ -433,7 +450,7 @@ static void waveform_detach(struct comedi_device *dev) struct waveform_private *devpriv = dev->private; if (devpriv) - waveform_ai_cancel(dev, dev->read_subdev); + del_timer_sync(&devpriv->timer); } static struct comedi_driver waveform_driver = {