From b609a5959f5ee44342d08ad37faba11bfbeb8b92 Mon Sep 17 00:00:00 2001
From: H Hartley Sweeten <hsweeten@visionengravers.com>
Date: Wed, 18 Sep 2013 11:48:41 -0700
Subject: [PATCH] staging: comedi: adl_pci6208: don't deadlock while waiting to
 write ao data

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@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@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 9150582fad068..059d7ea9503d1 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));
 	}
-- 
2.30.2