Commit b609a595 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman
Browse files

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: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 20fb170b
Loading
Loading
Loading
Loading
+21 −4
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@ Configuration Options: not applicable, uses PCI auto config
*/
*/


#include <linux/module.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci.h>


#include "../comedidev.h"
#include "../comedidev.h"
@@ -82,6 +83,21 @@ struct pci6208_private {
	unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS];
	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,
static int pci6208_ao_winsn(struct comedi_device *dev,
			    struct comedi_subdevice *s,
			    struct comedi_subdevice *s,
			    struct comedi_insn *insn, unsigned int *data)
			    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);
	int chan = CR_CHAN(insn->chanspec);
	unsigned int invert = 1 << (16 - 1);
	unsigned int invert = 1 << (16 - 1);
	unsigned int val = devpriv->ao_readback[chan];
	unsigned int val = devpriv->ao_readback[chan];
	unsigned short status;
	int ret;
	int i;
	int i;


	for (i = 0; i < insn->n; i++) {
	for (i = 0; i < insn->n; i++) {
		val = data[i];
		val = data[i];


		do {
		/* D/A transfer rate is 2.2us, wait up to 10us */
			status = inw(dev->iobase + PCI6208_AO_STATUS);
		ret = pci6208_ao_wait_for_data_send(dev, 10);
		} while (status & PCI6208_AO_STATUS_DATA_SEND);
		if (ret)
			return ret;


		outw(val ^ invert, dev->iobase + PCI6208_AO_CONTROL(chan));
		outw(val ^ invert, dev->iobase + PCI6208_AO_CONTROL(chan));
	}
	}