From 9a12cd06b9b63714ddfa1c0b85e3433442b1b4a8 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Sun, 27 Feb 2005 22:05:51 +0000 Subject: [PATCH] patch from Ian Abbot : I think it's probably a bad idea for my amplc_dio200 driver to call comedi_event() while it's holding a spinlock. The call to comedi_event could call a kcomedilib client's callback function, which might do something that requires the same spinlock, leading to a deadlock. The attached patch moves the calls to comedi_event() to a safe point after the spinlock is released. --- comedi/drivers/amplc_dio200.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/comedi/drivers/amplc_dio200.c b/comedi/drivers/amplc_dio200.c index 7a27fbe9..ae638e5a 100644 --- a/comedi/drivers/amplc_dio200.c +++ b/comedi/drivers/amplc_dio200.c @@ -364,19 +364,20 @@ dio200_stop_intr(comedi_device *dev, comedi_subdevice *s) /* * Called to start acquisition for an 'INTERRUPT' subdevice. */ -static void +static int dio200_start_intr(comedi_device *dev, comedi_subdevice *s) { unsigned int n; unsigned isn_bits; dio200_subdev_intr *subpriv = s->private; comedi_cmd *cmd = &s->async->cmd; + int retval = 0; if (!subpriv->continuous && subpriv->stopcount == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s, s->async->events); subpriv->active = 0; + retval = 1; } else { /* Determine interrupt sources to enable. */ isn_bits = 0; @@ -390,6 +391,8 @@ dio200_start_intr(comedi_device *dev, comedi_subdevice *s) subpriv->enabled_isns = isn_bits; outb(isn_bits, subpriv->iobase); } + + return retval; } /* @@ -401,6 +404,7 @@ dio200_inttrig_start_intr(comedi_device *dev, comedi_subdevice *s, { dio200_subdev_intr *subpriv; unsigned long flags; + int event = 0; if (trignum != 0) return -EINVAL; @@ -409,10 +413,14 @@ dio200_inttrig_start_intr(comedi_device *dev, comedi_subdevice *s, comedi_spin_lock_irqsave(&subpriv->spinlock, flags); s->async->inttrig = 0; if (subpriv->active) { - dio200_start_intr(dev, s); + event = dio200_start_intr(dev, s); } comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + if (event) { + comedi_event(dev, s, s->async->events); + } + return 1; } @@ -427,11 +435,13 @@ dio200_handle_read_intr(comedi_device *dev, comedi_subdevice *s) unsigned triggered; unsigned intstat; unsigned cur_enabled; + unsigned int oldevents; unsigned long flags; triggered = 0; comedi_spin_lock_irqsave(&subpriv->spinlock, flags); + oldevents = s->async->events; /* * Collect interrupt sources that have triggered and disable them * temporarily. Loop around until no extra interrupt sources have @@ -497,15 +507,15 @@ dio200_handle_read_intr(comedi_device *dev, comedi_subdevice *s) } } } - - if (s->async->events) { - comedi_event(dev, s, s->async->events); - } } } } comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + if (oldevents != s->async->events) { + comedi_event(dev, s, s->async->events); + } + return (triggered != 0); } @@ -630,6 +640,7 @@ dio200_subdev_intr_cmd(comedi_device *dev, comedi_subdevice *s) comedi_cmd *cmd = &s->async->cmd; dio200_subdev_intr *subpriv = s->private; unsigned long flags; + int event = 0; comedi_spin_lock_irqsave(&subpriv->spinlock, flags); subpriv->active = 1; @@ -654,11 +665,15 @@ dio200_subdev_intr_cmd(comedi_device *dev, comedi_subdevice *s) break; default: /* TRIG_NOW */ - dio200_start_intr(dev, s); + event = dio200_start_intr(dev, s); break; } comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + if (event) { + comedi_event(dev, s, s->async->events); + } + return 0; } -- 2.26.2