[PATCH 2/9] staging: comedi: adl_pci6208: don't deadlock while waiting to write ao data

H Hartley Sweeten hsweeten at visionengravers.com
Wed Sep 18 18:48:41 UTC 2013


Remove a possible deadlock while waiting to write the analog output data.

The data transfer rate for every D/A data write in this driver is 2.2us.
Wait up to 10us for the board to be ready then and return -ETIME.

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/adl_pci6208.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 9150582..059d7ea 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -39,6 +39,7 @@ References:
 */
 
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -82,6 +83,21 @@ struct pci6208_private {
 	unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS];
 };
 
+static int pci6208_ao_wait_for_data_send(struct comedi_device *dev,
+					 unsigned int timeout)
+{
+	unsigned int status;
+
+	while (timeout--) {
+		status = inw(dev->iobase + PCI6208_AO_STATUS);
+		if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0)
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIME;
+}
+
 static int pci6208_ao_winsn(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
 			    struct comedi_insn *insn, unsigned int *data)
@@ -90,15 +106,16 @@ static int pci6208_ao_winsn(struct comedi_device *dev,
 	int chan = CR_CHAN(insn->chanspec);
 	unsigned int invert = 1 << (16 - 1);
 	unsigned int val = devpriv->ao_readback[chan];
-	unsigned short status;
+	int ret;
 	int i;
 
 	for (i = 0; i < insn->n; i++) {
 		val = data[i];
 
-		do {
-			status = inw(dev->iobase + PCI6208_AO_STATUS);
-		} while (status & PCI6208_AO_STATUS_DATA_SEND);
+		/* D/A transfer rate is 2.2us, wait up to 10us */
+		ret = pci6208_ao_wait_for_data_send(dev, 10);
+		if (ret)
+			return ret;
 
 		outw(val ^ invert, dev->iobase + PCI6208_AO_CONTROL(chan));
 	}
-- 
1.8.3.2



More information about the devel mailing list