On 2014-02-06 23:49, H Hartley Sweeten wrote:
Use comedi_timeout() to wait for the analog input end-of-conversion. Combine the logic for the pcl812 and acl812 end-of-conversion in the helper function to simplify the driver. The interrupt routine also uses the timeout check to make sure data is actually available. Using NULL here for the 'insn' is safe since nothing uses it.
I don't think you can rely on jiffies being updated in the interrupt routine.
Signed-off-by: H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx> Cc: Ian Abbott <abbotti@xxxxxxxxx> Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/staging/comedi/drivers/pcl812.c | 95 ++++++++++++++++----------------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 53613b38..3fa429a 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -394,16 +394,35 @@ static void setup_range_channel(struct comedi_device *dev, unsigned int rangechan, char wait); static int pcl812_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -/* -============================================================================== -*/ + +static int pcl812_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct pcl812_private *devpriv = dev->private; + unsigned int status; + + if (devpriv->ai_is16b) { + status = inb(dev->iobase + ACL8216_STATUS); + if ((status & ACL8216_DRDY) == 0) + return 0; + } else { + status = inb(dev->iobase + PCL812_AD_HI); + if ((status & PCL812_DRDY) == 0) + return 0; + } + return -EBUSY; +} + static int pcl812_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pcl812_private *devpriv = dev->private; + int ret = 0; int n; - int timeout, hi; + int hi; /* select software trigger */ outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); @@ -413,33 +432,27 @@ static int pcl812_ai_insn_read(struct comedi_device *dev, /* start conversion */ outb(255, dev->iobase + PCL812_SOFTTRIG); udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - hi = inb(dev->iobase + PCL812_AD_HI); - if (!(hi & PCL812_DRDY)) - goto conv_finish; - udelay(1); + + ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0); + if (ret) { + dev_dbg(dev->class_dev, "A/D insn read timeout\n"); + break; } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return -ETIME; -conv_finish: + hi = inb(dev->iobase + PCL812_AD_HI); data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); } outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return n; + + return ret ? ret : n; } -/* -============================================================================== -*/ static int acl8216_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + int ret = 0; int n; - int timeout; /* select software trigger */ outb(1, dev->iobase + PCL812_MODE); @@ -449,23 +462,20 @@ static int acl8216_ai_insn_read(struct comedi_device *dev, /* start conversion */ outb(255, dev->iobase + PCL812_SOFTTRIG); udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) - goto conv_finish; - udelay(1); + + ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0); + if (ret) { + dev_dbg(dev->class_dev, "A/D insn read timeout\n"); + break; } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(0, dev->iobase + PCL812_MODE); - return -ETIME; -conv_finish: data[n] = (inb(dev->iobase + PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO); } outb(0, dev->iobase + PCL812_MODE); - return n; + + return ret ? ret : n; } /* @@ -767,37 +777,22 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) { - char err = 1; - unsigned int mask, timeout; + unsigned int mask; struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; unsigned int next_chan; + int ret; s->async->events = 0; - timeout = 50; /* wait max 50us, it must finish under 33us */ - if (devpriv->ai_is16b) { + if (devpriv->ai_is16b) mask = 0xffff; - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } else { + else mask = 0x0fff; - while (timeout--) { - if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } - if (err) { + ret = comedi_timeout(dev, s, NULL, pcl812_ai_eoc, 0); + if (ret) { dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); pcl812_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-- -=( Ian Abbott @ MEV Ltd. E-mail: <abbotti@xxxxxxxxx> )=- -=( Tel: +44 (0)161 477 1898 FAX: +44 (0)161 718 3587 )=- _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel