From 67562be5054f325324197cfd0f478cdc76ed57e8 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 10 Feb 2014 11:49:24 -0700 Subject: [PATCH] staging: comedi: addi_apci_3xx: use comedi_timeout() Use comedi_timeout() to wait for the analog input and output end-of- conversions. This prevents a deadlock condition that could occur by providing a timeout in case the end-of-conversion does not happen. Signed-off-by: H Hartley Sweeten Cc: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- .../staging/comedi/drivers/addi_apci_3xxx.c | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index 1f3b668f7f1f..6dc11c407f57 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -434,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) return 0; } +static int apci3xxx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 20); + if (status & 0x1) + return 0; + return -EBUSY; +} + static int apci3xxx_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct apci3xxx_private *devpriv = dev->private; - unsigned int val; int ret; int i; @@ -453,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev, writel(0x80000, devpriv->mmio + 8); /* Wait the EOS */ - do { - val = readl(devpriv->mmio + 20); - val &= 0x1; - } while (!val); + ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0); + if (ret) + return ret; /* Read the analog value */ data[i] = readl(devpriv->mmio + 28); @@ -622,6 +634,20 @@ static int apci3xxx_ai_cancel(struct comedi_device *dev, return 0; } +static int apci3xxx_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 96); + if (status & 0x100) + return 0; + return -EBUSY; +} + static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -630,7 +656,7 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct apci3xxx_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int status; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -641,9 +667,9 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, writel((data[i] << 8) | chan, devpriv->mmio + 100); /* Wait the end of transfer */ - do { - status = readl(devpriv->mmio + 96); - } while ((status & 0x100) != 0x100); + ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0); + if (ret) + return ret; } return insn->n;