|
@@ -228,122 +228,6 @@ struct das800_private {
|
|
|
volatile int do_bits; /* digital output bits */
|
|
|
};
|
|
|
|
|
|
-static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
|
|
|
-
|
|
|
-static irqreturn_t das800_interrupt(int irq, void *d);
|
|
|
-static void enable_das800(struct comedi_device *dev);
|
|
|
-static void disable_das800(struct comedi_device *dev);
|
|
|
-
|
|
|
-/* interrupt service routine */
|
|
|
-static irqreturn_t das800_interrupt(int irq, void *d)
|
|
|
-{
|
|
|
- short i; /* loop index */
|
|
|
- short dataPoint = 0;
|
|
|
- struct comedi_device *dev = d;
|
|
|
- const struct das800_board *thisboard = comedi_board(dev);
|
|
|
- struct das800_private *devpriv = dev->private;
|
|
|
- struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */
|
|
|
- struct comedi_async *async;
|
|
|
- int status;
|
|
|
- unsigned long irq_flags;
|
|
|
- static const int max_loops = 128; /* half-fifo size for cio-das802/16 */
|
|
|
- /* flags */
|
|
|
- int fifo_empty = 0;
|
|
|
- int fifo_overflow = 0;
|
|
|
-
|
|
|
- status = inb(dev->iobase + DAS800_STATUS);
|
|
|
- /* if interrupt was not generated by board or driver not attached, quit */
|
|
|
- if (!(status & IRQ))
|
|
|
- return IRQ_NONE;
|
|
|
- if (!(dev->attached))
|
|
|
- return IRQ_HANDLED;
|
|
|
-
|
|
|
- /* wait until here to initialize async, since we will get null dereference
|
|
|
- * if interrupt occurs before driver is fully attached!
|
|
|
- */
|
|
|
- async = s->async;
|
|
|
-
|
|
|
- /* if hardware conversions are not enabled, then quit */
|
|
|
- spin_lock_irqsave(&dev->spinlock, irq_flags);
|
|
|
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */
|
|
|
- status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
|
|
|
- /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
|
|
|
- if (status == 0) {
|
|
|
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
- return IRQ_HANDLED;
|
|
|
- }
|
|
|
-
|
|
|
- /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
|
|
|
- for (i = 0; i < max_loops; i++) {
|
|
|
- /* read 16 bits from dev->iobase and dev->iobase + 1 */
|
|
|
- dataPoint = inb(dev->iobase + DAS800_LSB);
|
|
|
- dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
|
|
|
- if (thisboard->resolution == 12) {
|
|
|
- fifo_empty = dataPoint & FIFO_EMPTY;
|
|
|
- fifo_overflow = dataPoint & FIFO_OVF;
|
|
|
- if (fifo_overflow)
|
|
|
- break;
|
|
|
- } else {
|
|
|
- fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */
|
|
|
- }
|
|
|
- if (fifo_empty)
|
|
|
- break;
|
|
|
- /* strip off extraneous bits for 12 bit cards */
|
|
|
- if (thisboard->resolution == 12)
|
|
|
- dataPoint = (dataPoint >> 4) & 0xfff;
|
|
|
- /* if there are more data points to collect */
|
|
|
- if (devpriv->count > 0 || devpriv->forever == 1) {
|
|
|
- /* write data point to buffer */
|
|
|
- cfc_write_to_buffer(s, dataPoint);
|
|
|
- if (devpriv->count > 0)
|
|
|
- devpriv->count--;
|
|
|
- }
|
|
|
- }
|
|
|
- async->events |= COMEDI_CB_BLOCK;
|
|
|
- /* check for fifo overflow */
|
|
|
- if (thisboard->resolution == 12) {
|
|
|
- fifo_overflow = dataPoint & FIFO_OVF;
|
|
|
- /* else cio-das802/16 */
|
|
|
- } else {
|
|
|
- fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
|
|
|
- }
|
|
|
- if (fifo_overflow) {
|
|
|
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
- comedi_error(dev, "DAS800 FIFO overflow");
|
|
|
- das800_cancel(dev, s);
|
|
|
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
|
|
|
- comedi_event(dev, s);
|
|
|
- async->events = 0;
|
|
|
- return IRQ_HANDLED;
|
|
|
- }
|
|
|
- if (devpriv->count > 0 || devpriv->forever == 1) {
|
|
|
- /* Re-enable card's interrupt.
|
|
|
- * We already have spinlock, so indirect addressing is safe */
|
|
|
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
|
|
|
- outb(CONTROL1_INTE | devpriv->do_bits,
|
|
|
- dev->iobase + DAS800_CONTROL1);
|
|
|
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
- /* otherwise, stop taking data */
|
|
|
- } else {
|
|
|
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
- disable_das800(dev); /* disable hardware triggered conversions */
|
|
|
- async->events |= COMEDI_CB_EOA;
|
|
|
- }
|
|
|
- comedi_event(dev, s);
|
|
|
- async->events = 0;
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
-static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
|
|
|
-{
|
|
|
- struct das800_private *devpriv = dev->private;
|
|
|
-
|
|
|
- devpriv->forever = 0;
|
|
|
- devpriv->count = 0;
|
|
|
- disable_das800(dev);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/* enable_das800 makes the card start taking hardware triggered conversions */
|
|
|
static void enable_das800(struct comedi_device *dev)
|
|
|
{
|
|
@@ -387,6 +271,16 @@ static int das800_set_frequency(struct comedi_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
|
|
|
+{
|
|
|
+ struct das800_private *devpriv = dev->private;
|
|
|
+
|
|
|
+ devpriv->forever = 0;
|
|
|
+ devpriv->count = 0;
|
|
|
+ disable_das800(dev);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int das800_ai_do_cmdtest(struct comedi_device *dev,
|
|
|
struct comedi_subdevice *s,
|
|
|
struct comedi_cmd *cmd)
|
|
@@ -564,6 +458,105 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static irqreturn_t das800_interrupt(int irq, void *d)
|
|
|
+{
|
|
|
+ short i; /* loop index */
|
|
|
+ short dataPoint = 0;
|
|
|
+ struct comedi_device *dev = d;
|
|
|
+ const struct das800_board *thisboard = comedi_board(dev);
|
|
|
+ struct das800_private *devpriv = dev->private;
|
|
|
+ struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */
|
|
|
+ struct comedi_async *async;
|
|
|
+ int status;
|
|
|
+ unsigned long irq_flags;
|
|
|
+ static const int max_loops = 128; /* half-fifo size for cio-das802/16 */
|
|
|
+ /* flags */
|
|
|
+ int fifo_empty = 0;
|
|
|
+ int fifo_overflow = 0;
|
|
|
+
|
|
|
+ status = inb(dev->iobase + DAS800_STATUS);
|
|
|
+ /* if interrupt was not generated by board or driver not attached, quit */
|
|
|
+ if (!(status & IRQ))
|
|
|
+ return IRQ_NONE;
|
|
|
+ if (!(dev->attached))
|
|
|
+ return IRQ_HANDLED;
|
|
|
+
|
|
|
+ /* wait until here to initialize async, since we will get null dereference
|
|
|
+ * if interrupt occurs before driver is fully attached!
|
|
|
+ */
|
|
|
+ async = s->async;
|
|
|
+
|
|
|
+ /* if hardware conversions are not enabled, then quit */
|
|
|
+ spin_lock_irqsave(&dev->spinlock, irq_flags);
|
|
|
+ outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */
|
|
|
+ status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
|
|
|
+ /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
|
|
|
+ if (status == 0) {
|
|
|
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
|
|
|
+ for (i = 0; i < max_loops; i++) {
|
|
|
+ /* read 16 bits from dev->iobase and dev->iobase + 1 */
|
|
|
+ dataPoint = inb(dev->iobase + DAS800_LSB);
|
|
|
+ dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
|
|
|
+ if (thisboard->resolution == 12) {
|
|
|
+ fifo_empty = dataPoint & FIFO_EMPTY;
|
|
|
+ fifo_overflow = dataPoint & FIFO_OVF;
|
|
|
+ if (fifo_overflow)
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */
|
|
|
+ }
|
|
|
+ if (fifo_empty)
|
|
|
+ break;
|
|
|
+ /* strip off extraneous bits for 12 bit cards */
|
|
|
+ if (thisboard->resolution == 12)
|
|
|
+ dataPoint = (dataPoint >> 4) & 0xfff;
|
|
|
+ /* if there are more data points to collect */
|
|
|
+ if (devpriv->count > 0 || devpriv->forever == 1) {
|
|
|
+ /* write data point to buffer */
|
|
|
+ cfc_write_to_buffer(s, dataPoint);
|
|
|
+ if (devpriv->count > 0)
|
|
|
+ devpriv->count--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ async->events |= COMEDI_CB_BLOCK;
|
|
|
+ /* check for fifo overflow */
|
|
|
+ if (thisboard->resolution == 12) {
|
|
|
+ fifo_overflow = dataPoint & FIFO_OVF;
|
|
|
+ /* else cio-das802/16 */
|
|
|
+ } else {
|
|
|
+ fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
|
|
|
+ }
|
|
|
+ if (fifo_overflow) {
|
|
|
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
+ comedi_error(dev, "DAS800 FIFO overflow");
|
|
|
+ das800_cancel(dev, s);
|
|
|
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
|
|
|
+ comedi_event(dev, s);
|
|
|
+ async->events = 0;
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ }
|
|
|
+ if (devpriv->count > 0 || devpriv->forever == 1) {
|
|
|
+ /* Re-enable card's interrupt.
|
|
|
+ * We already have spinlock, so indirect addressing is safe */
|
|
|
+ outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
|
|
|
+ outb(CONTROL1_INTE | devpriv->do_bits,
|
|
|
+ dev->iobase + DAS800_CONTROL1);
|
|
|
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
+ /* otherwise, stop taking data */
|
|
|
+ } else {
|
|
|
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
|
|
|
+ disable_das800(dev); /* disable hardware triggered conversions */
|
|
|
+ async->events |= COMEDI_CB_EOA;
|
|
|
+ }
|
|
|
+ comedi_event(dev, s);
|
|
|
+ async->events = 0;
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
static int das800_ai_rinsn(struct comedi_device *dev,
|
|
|
struct comedi_subdevice *s, struct comedi_insn *insn,
|
|
|
unsigned int *data)
|