[PATCH 05/17] staging: comedi: quatech_daqp_cs: don't use interrupts for ai (*insn_read)

H Hartley Sweeten hsweeten at visionengravers.com
Thu Oct 1 17:58:54 UTC 2015


The comedi (*insn_read) functions are supposed to do simple one-shot
reading of an analog input channel. Currently this driver enables
interrupts and uses wait_for_completion_interruptible() to allow the
interrupt routine to let the analog input (*insn_read) know that
the end-of-conversion has occured.

Simplify the function by using the comedi_timeout() helper to check
the aux status register to see when the conversion is finished.

Signed-off-by: H Hartley Sweeten <hsweeten at visionengravers.com>
Cc: Ian Abbott <abbotti at mev.co.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 drivers/staging/comedi/drivers/quatech_daqp_cs.c | 59 +++++++++++-------------
 1 file changed, 28 insertions(+), 31 deletions(-)

diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index de28224..dbb8ffc 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -48,8 +48,6 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308
 */
 
 #include <linux/module.h>
-#include <linux/semaphore.h>
-#include <linux/completion.h>
 
 #include "../comedi_pcmcia.h"
 
@@ -59,8 +57,6 @@ struct daqp_private {
 	int stop;
 
 	enum { semaphore, buffer } interrupt_mode;
-
-	struct completion eos;
 };
 
 /* The DAQP communicates with the system through a 16 byte I/O window. */
@@ -175,15 +171,6 @@ static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 	return 0;
 }
 
-/* Interrupt handler
- *
- * Operates in one of two modes.  If devpriv->interrupt_mode is
- * 'semaphore', just signal the devpriv->eos completion and return
- * (one-shot mode).  Otherwise (continuous mode), read data in from
- * the card, transfer it to the buffer provided by the higher-level
- * comedi kernel module, and signal various comedi callback routines,
- * which run pretty quick.
- */
 static enum irqreturn daqp_interrupt(int irq, void *dev_id)
 {
 	struct comedi_device *dev = dev_id;
@@ -198,7 +185,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
 
 	switch (devpriv->interrupt_mode) {
 	case semaphore:
-		complete(&devpriv->eos);
 		break;
 
 	case buffer:
@@ -270,15 +256,27 @@ static void daqp_ai_set_scanlist(struct comedi_device *dev,
 	}
 }
 
-/* One-shot analog data acquisition routine */
+static int daqp_ai_eos(struct comedi_device *dev,
+		       struct comedi_subdevice *s,
+		       struct comedi_insn *insn,
+		       unsigned long context)
+{
+	unsigned int status;
+
+	status = inb(dev->iobase + DAQP_AUX);
+	if (status & DAQP_AUX_CONVERSION)
+		return 0;
+	return -EBUSY;
+}
 
 static int daqp_ai_insn_read(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn, unsigned int *data)
+			     struct comedi_insn *insn,
+			     unsigned int *data)
 {
 	struct daqp_private *devpriv = dev->private;
+	int ret = 0;
 	int i;
-	int v;
 	int counter = 10000;
 
 	if (devpriv->stop)
@@ -296,12 +294,8 @@ static int daqp_ai_insn_read(struct comedi_device *dev,
 
 	outb(DAQP_COMMAND_RSTF, dev->iobase + DAQP_COMMAND);
 
-	/* Set trigger */
-
-	v = DAQP_CONTROL_TRIGGER_ONESHOT | DAQP_CONTROL_TRIGGER_INTERNAL
-	    | DAQP_CONTROL_PACER_100kHz | DAQP_CONTROL_EOS_INT_ENABLE;
-
-	outb(v, dev->iobase + DAQP_CONTROL);
+	/* one-shot internal trigger, no pacer, no interrupts */
+	outb(0, dev->iobase + DAQP_CONTROL);
 
 	/* Reset any pending interrupts (my card has a tendency to require
 	 * require multiple reads on the status register to achieve this)
@@ -316,25 +310,28 @@ static int daqp_ai_insn_read(struct comedi_device *dev,
 		return -1;
 	}
 
-	init_completion(&devpriv->eos);
-	devpriv->interrupt_mode = semaphore;
-
 	for (i = 0; i < insn->n; i++) {
 		/* Start conversion */
 		outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA,
 		     dev->iobase + DAQP_COMMAND);
 
-		/* Wait for interrupt service routine to unblock completion */
-		/* Maybe could use a timeout here, but it's interruptible */
-		if (wait_for_completion_interruptible(&devpriv->eos))
-			return -EINTR;
+		ret = comedi_timeout(dev, s, insn, daqp_ai_eos, 0);
+		if (ret)
+			break;
+
+		/* clear the status event flags */
+		inb(dev->iobase + DAQP_STATUS);
 
 		data[i] = inb(dev->iobase + DAQP_FIFO);
 		data[i] |= inb(dev->iobase + DAQP_FIFO) << 8;
 		data[i] ^= 0x8000;
 	}
 
-	return insn->n;
+	/* stop any conversions and clear the status event flags */
+	outb(DAQP_COMMAND_STOP, dev->iobase + DAQP_COMMAND);
+	inb(dev->iobase + DAQP_STATUS);
+
+	return ret ? ret : insn->n;
 }
 
 /* This function converts ns nanoseconds to a counter value suitable
-- 
2.5.1



More information about the devel mailing list