From: H Hartley Sweeten Date: Wed, 18 Sep 2013 18:48:41 +0000 (-0700) Subject: staging: comedi: adl_pci6208: don't deadlock while waiting to write ao data X-Git-Tag: firefly_0821_release~176^2~5057^2~691 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b609a5959f5ee44342d08ad37faba11bfbeb8b92;p=firefly-linux-kernel-4.4.55.git 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 Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 9150582fad06..059d7ea9503d 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -39,6 +39,7 @@ References: */ #include +#include #include #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)); }