summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH Hartley Sweeten <hsweeten@visionengravers.com>2014-11-04 10:54:33 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-07 09:34:01 -0800
commit89e9057b50369474c1e701faccdeedf08566ec57 (patch)
tree1d6252ff29084eb7438e8391d197813ed13b2d8f
parent22f75dac46e0691ef03e44d27d21d2b860cc15fe (diff)
staging: comedi: addi_apci_3120: fix apci3120_ai_insn_read()
Now that the scanning and interrupt support have been removed from this function it can be refactored to work correctly. The comedi core expects (*insn_read) functions to read insn->n values from the hardware and return the number of samples read. This function currently just reads one sample but it returns insn->n. Fix this function to work like the core expects. Use comedi_timeout() to prevent a possible deadlock in the loop that waits for the end-of-conversion. 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>
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c90
1 files changed, 40 insertions, 50 deletions
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index 51cdecb211d6..5fb884835643 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -139,6 +139,19 @@ static int apci3120_setup_chan_list(struct comedi_device *dev,
return 1; /* we can serve this with scan logic */
}
+static int apci3120_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + APCI3120_RD_STATUS);
+ if ((status & APCI3120_EOC) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int apci3120_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -146,67 +159,44 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
{
struct apci3120_private *devpriv = dev->private;
unsigned int divisor;
- unsigned int ns;
- unsigned short us_TmpValue;
-
- /* fix conversion time to 10 us */
- ns = 10000;
-
- /* Clear software registers */
- devpriv->timer_mode = 0;
- devpriv->mode = 0;
-
- if (insn->unused[0] == 222) { /* second insn read */
- } else {
- devpriv->tsk_Current = current; /* Save the current process task structure */
-
- divisor = apci3120_ns_to_timer(dev, 0, ns, CMDF_ROUND_NEAREST);
-
- us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
-
- switch (us_TmpValue) {
-
- case APCI3120_EOC_MODE:
- apci3120_ai_reset_fifo(dev);
-
- /* Initialize the sequence array */
- if (!apci3120_setup_chan_list(dev, s, 1,
- &insn->chanspec))
- return -EINVAL;
-
- /* Initialize Timer 0 mode 4 */
- apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE4);
+ int ret;
+ int i;
- outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
+ /* set mode for A/D conversions by software trigger with timer 0 */
+ devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC |
+ APCI3120_MODE_TIMER2_AS_TIMER;
+ outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
- apci3120_timer_enable(dev, 0, true);
+ /* load chanlist for single channel scan */
+ if (!apci3120_setup_chan_list(dev, s, 1, &insn->chanspec))
+ return -EINVAL;
- /* Set the conversion time */
- apci3120_timer_write(dev, 0, divisor);
+ /*
+ * Timer 0 is used in MODE4 (software triggered strobe) to set the
+ * conversion time for each acquisition. Each conversion is triggered
+ * when the divisor is written to the timer, The conversion is done
+ * when the EOC bit in the status register is '0'.
+ */
+ apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE4);
+ apci3120_timer_enable(dev, 0, true);
- us_TmpValue =
- (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
+ /* fixed conversion time of 10 us */
+ divisor = apci3120_ns_to_timer(dev, 0, 10000, CMDF_ROUND_NEAREST);
- do {
- /* Waiting for the end of conversion */
- us_TmpValue = inw(dev->iobase +
- APCI3120_RD_STATUS);
- } while ((us_TmpValue & APCI3120_EOC) == APCI3120_EOC);
+ apci3120_ai_reset_fifo(dev);
- /* Read the result in FIFO and put it in insn data pointer */
- us_TmpValue = inw(dev->iobase + 0);
- *data = us_TmpValue;
+ for (i = 0; i < insn->n; i++) {
+ /* trigger conversion */
+ apci3120_timer_write(dev, 0, divisor);
- apci3120_ai_reset_fifo(dev);
- break;
- default:
- dev_err(dev->class_dev, "inputs wrong\n");
+ ret = comedi_timeout(dev, s, insn, apci3120_ai_eoc, 0);
+ if (ret)
+ return ret;
- }
+ data[i] = inw(dev->iobase + 0);
}
return insn->n;
-
}
static int apci3120_reset(struct comedi_device *dev)