Fixed an issue with jiffies vs miliseconds for the timeout value
[comedi.git] / comedi / drivers / rti800.c
index d499349499ee7b51c824ed1ffc2ff5f4d19da4ec..572b0d0256dd6f8cb6694a762e41720915ba9cb5 100644 (file)
@@ -1,9 +1,9 @@
 /*
-   module/rti800.c
-   hardware driver for Analog Devices RTI-800/815 board
+   comedi/drivers/rti800.c
+   Hardware driver for Analog Devices RTI-800/815 board
 
    COMEDI - Linux Control and Measurement Device Interface
-   Copyright (C) 1998 David A. Schleef <ds@stm.lbl.gov>
+   Copyright (C) 1998 David A. Schleef <ds@schleef.org>
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
  */
 /*
-Driver: rti800.o
+Driver: rti800
 Description: Analog Devices RTI-800/815
 Author: ds
 Status: unknown
-Drivers: (Analog Devices) RTI-800 (rti800), RTI-815 (rti815)
+Updated: Fri, 05 Sep 2008 14:50:44 +0100
+Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
 
 Configuration options:
   [0] - I/O port base address
@@ -44,27 +45,16 @@ Configuration options:
   [5] - DAC 0 range
           0 = [-10,10]
           1 = [0,10]
-  [5] - DAC 0 encoding
+  [6] - DAC 0 encoding
           0 = two's complement
           1 = straight binary
-  [6] - DAC 1 range (same as DAC 0)
-  [7] - DAC 1 encoding (same as DAC 0)
+  [7] - DAC 1 range (same as DAC 0)
+  [8] - DAC 1 encoding (same as DAC 0)
 */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/timer.h>
-#include <asm/io.h>
 #include <linux/comedidev.h>
 
+#include <linux/ioport.h>
 
 #define RTI800_SIZE 16
 
@@ -84,7 +74,6 @@ Configuration options:
 #define RTI800_9513A_CNTRL 13
 #define RTI800_9513A_STATUS 13
 
-
 /*
  * flags for CSR register
  */
@@ -107,49 +96,54 @@ Configuration options:
 
 #include "am9513.h"
 
-static comedi_lrange range_rti800_ai_10_bipolar = { 4, {
-       BIP_RANGE( 10 ),
-       BIP_RANGE( 1 ),
-       BIP_RANGE( 0.1 ),
-       BIP_RANGE( 0.02 )
-}};
-static comedi_lrange range_rti800_ai_5_bipolar = { 4, {
-       BIP_RANGE( 5 ),
-       BIP_RANGE( 0.5 ),
-       BIP_RANGE( 0.05 ),
-       BIP_RANGE( 0.01 )
-}};
-static comedi_lrange range_rti800_ai_unipolar = { 4, {
-       UNI_RANGE( 10 ),
-       UNI_RANGE( 1 ),
-       UNI_RANGE( 0.1 ),
-       UNI_RANGE( 0.02 )
-}};
-
-typedef struct{
-       char *name;
+static const comedi_lrange range_rti800_ai_10_bipolar = { 4, {
+                       BIP_RANGE(10),
+                       BIP_RANGE(1),
+                       BIP_RANGE(0.1),
+                       BIP_RANGE(0.02)
+       }
+};
+static const comedi_lrange range_rti800_ai_5_bipolar = { 4, {
+                       BIP_RANGE(5),
+                       BIP_RANGE(0.5),
+                       BIP_RANGE(0.05),
+                       BIP_RANGE(0.01)
+       }
+};
+static const comedi_lrange range_rti800_ai_unipolar = { 4, {
+                       UNI_RANGE(10),
+                       UNI_RANGE(1),
+                       UNI_RANGE(0.1),
+                       UNI_RANGE(0.02)
+       }
+};
+
+typedef struct {
+       const char *name;
        int has_ao;
-}boardtype;
-static boardtype boardtypes[]={
-       { "rti800", 0 },
-       { "rti815", 1 },
+} boardtype;
+static const boardtype boardtypes[] = {
+       {"rti800", 0},
+       {"rti815", 1},
 };
-#define this_board ((boardtype *)dev->board_ptr)
-
-static int rti800_attach(comedi_device *dev,comedi_devconfig *it);
-static int rti800_detach(comedi_device *dev);
-static comedi_driver driver_rti800={
-       driver_name:    "rti800",
-       module:         THIS_MODULE,
-       attach:         rti800_attach,
-       detach:         rti800_detach,
-       num_names:      sizeof(boardtypes)/sizeof(boardtype),
-       board_name:     boardtypes,
-       offset:         sizeof(boardtype),
+
+#define this_board ((const boardtype *)dev->board_ptr)
+
+static int rti800_attach(comedi_device * dev, comedi_devconfig * it);
+static int rti800_detach(comedi_device * dev);
+static comedi_driver driver_rti800 = {
+      driver_name:"rti800",
+      module:THIS_MODULE,
+      attach:rti800_attach,
+      detach:rti800_detach,
+      num_names:sizeof(boardtypes) / sizeof(boardtype),
+      board_name:&boardtypes[0].name,
+      offset:sizeof(boardtype),
 };
+
 COMEDI_INITCLEANUP(driver_rti800);
 
-static void rti800_interrupt(int irq, void *dev, struct pt_regs *regs);
+static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG);
 
 typedef struct {
        enum {
@@ -167,55 +161,67 @@ typedef struct {
        enum {
                dac_2comp, dac_straight
        } dac0_coding, dac1_coding;
-       comedi_lrange * ao_range_type_list[2];
+       const comedi_lrange *ao_range_type_list[2];
        lsampl_t ao_readback[2];
+       int muxgain_bits;
 } rti800_private;
 
 #define devpriv ((rti800_private *)dev->private)
 
-#define RTI800_TIMEOUT 10
+#define RTI800_TIMEOUT 100
 
-static void rti800_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG)
 {
-
-
+       return IRQ_HANDLED;
 }
 
-static int gaindelay[]={10,20,40,80};
+// settling delay times in usec for different gains
+static const int gaindelay[] = { 10, 20, 40, 80 };
 
-static int rti800_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int rti800_ai_insn_read(comedi_device * dev, comedi_subdevice * s,
+       comedi_insn * insn, lsampl_t * data)
 {
-       int i,t;
+       int i, t;
        int status;
        int chan = CR_CHAN(insn->chanspec);
-       int gain = CR_RANGE(insn->chanspec);
+       unsigned gain = CR_RANGE(insn->chanspec);
+       unsigned muxgain_bits;
 
        inb(dev->iobase + RTI800_ADCHI);
-       outb(0,dev->iobase+RTI800_CLRFLAGS);
-
-       outb(chan | (gain << 5), dev->iobase + RTI800_MUXGAIN);
-
-       /* contrary to the docs, there needs to be a delay here */
-       udelay(gaindelay[gain]);
+       outb(0, dev->iobase + RTI800_CLRFLAGS);
+
+       muxgain_bits = chan | (gain << 5);
+       if (muxgain_bits != devpriv->muxgain_bits) {
+               devpriv->muxgain_bits = muxgain_bits;
+               outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
+               /* without a delay here, the RTI_OVERRUN bit
+                * gets set, and you will have an error. */
+               if (insn->n > 0) {
+                       BUG_ON(gain >=
+                               sizeof(gaindelay) / sizeof(gaindelay[0]));
+                       comedi_udelay(gaindelay[gain]);
+               }
+       }
 
-       for(i=0;i<insn->n;i++){
+       for (i = 0; i < insn->n; i++) {
                outb(0, dev->iobase + RTI800_CONVERT);
-               for (t = RTI800_TIMEOUT; t; t--) {
-                       status=inb(dev->iobase+RTI800_CSR);
-                       if(status & RTI800_OVERRUN){
-                               rt_printk("rti800: a/d overflow\n");
-                               outb(0,dev->iobase+RTI800_CLRFLAGS);
+               for (t = RTI800_TIMEOUT; t; t--) {
+                       status = inb(dev->iobase + RTI800_CSR);
+                       if (status & RTI800_OVERRUN) {
+                               rt_printk("rti800: a/d overrun\n");
+                               outb(0, dev->iobase + RTI800_CLRFLAGS);
                                return -EIO;
                        }
-                       if (status & RTI800_DONE)break;
+                       if (status & RTI800_DONE)
+                               break;
+                       comedi_udelay(1);
                }
-               if(t){
+               if (t == 0) {
                        rt_printk("rti800: timeout\n");
                        return -ETIME;
                }
                data[i] = inb(dev->iobase + RTI800_ADCLO);
-               data[i] = (0xf & inb(dev->iobase + RTI800_ADCHI))<<8;
+               data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
 
                if (devpriv->adc_coding == adc_2comp) {
                        data[i] ^= 0x800;
@@ -225,61 +231,65 @@ static int rti800_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
        return i;
 }
 
-static int rti800_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int rti800_ao_insn_read(comedi_device * dev, comedi_subdevice * s,
+       comedi_insn * insn, lsampl_t * data)
 {
        int i;
-       int chan=CR_CHAN(insn->chanspec);
+       int chan = CR_CHAN(insn->chanspec);
 
-       for(i=0;i<insn->n;i++)
+       for (i = 0; i < insn->n; i++)
                data[i] = devpriv->ao_readback[chan];
 
        return i;
 }
 
-static int rti800_ao_insn_write(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int rti800_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
+       comedi_insn * insn, lsampl_t * data)
 {
-       int chan=CR_CHAN(insn->chanspec);
+       int chan = CR_CHAN(insn->chanspec);
        int d;
        int i;
 
-       for(i=0;i<insn->n;i++){
+       for (i = 0; i < insn->n; i++) {
                devpriv->ao_readback[chan] = d = data[i];
                if (devpriv->dac0_coding == dac_2comp) {
                        d ^= 0x800;
                }
-               outb(d & 0xff, dev->iobase + chan?RTI800_DAC1LO:RTI800_DAC0LO);
-               outb(d >> 8, dev->iobase + chan?RTI800_DAC1HI:RTI800_DAC0HI);
+               outb(d & 0xff,
+                       dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
+               outb(d >> 8,
+                       dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
        }
        return i;
 }
 
-static int rti800_di_insn_bits(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int rti800_di_insn_bits(comedi_device * dev, comedi_subdevice * s,
+       comedi_insn * insn, lsampl_t * data)
 {
-       if(insn->n!=2)return -EINVAL;
+       if (insn->n != 2)
+               return -EINVAL;
        data[1] = inb(dev->iobase + RTI800_DI);
-
        return 2;
 }
 
-static int rti800_do_insn_bits(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int rti800_do_insn_bits(comedi_device * dev, comedi_subdevice * s,
+       comedi_insn * insn, lsampl_t * data)
 {
-       if(insn->n!=2)return -EINVAL;
+       if (insn->n != 2)
+               return -EINVAL;
 
-       if(data[0]){
+       if (data[0]) {
                s->state &= ~data[0];
-               s->state &= data[0]&data[1];
+               s->state |= data[0] & data[1];
                /* Outputs are inverted... */
                outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
        }
 
+       data[1] = s->state;
+
        return 2;
 }
 
-
 /*
    options[0] - I/O port
    options[1] - irq
@@ -299,18 +309,17 @@ static int rti800_do_insn_bits(comedi_device *dev,comedi_subdevice *s,
 
 static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
 {
-       int irq;
-       int iobase;
+       unsigned int irq;
+       unsigned long iobase;
        int ret;
        comedi_subdevice *s;
 
        iobase = it->options[0];
-       printk("comedi%d: rti800: 0x%04x ", dev->minor, iobase);
-       if (check_region(iobase, RTI800_SIZE) < 0) {
+       printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase);
+       if (!request_region(iobase, RTI800_SIZE, "rti800")) {
                printk("I/O port conflict\n");
                return -EIO;
        }
-       request_region(iobase, RTI800_SIZE, "rti800");
        dev->iobase = iobase;
 
 #ifdef DEBUG
@@ -318,32 +327,33 @@ static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
                inb(dev->iobase + 0),
                inb(dev->iobase + 1),
                inb(dev->iobase + 2),
-               inb(dev->iobase + 3),
-               inb(dev->iobase + 4));
+               inb(dev->iobase + 3), inb(dev->iobase + 4));
 #endif
 
-       outb(0,dev->iobase+RTI800_CSR);
-       inb(dev->iobase+RTI800_ADCHI);
-       outb(0,dev->iobase+RTI800_CLRFLAGS);
-
-       irq=it->options[1];
-       if(irq>0){
-               printk("( irq = %d )\n",irq);
-               if((ret=comedi_request_irq(irq,rti800_interrupt, 0, "rti800", dev))<0)
+       outb(0, dev->iobase + RTI800_CSR);
+       inb(dev->iobase + RTI800_ADCHI);
+       outb(0, dev->iobase + RTI800_CLRFLAGS);
+
+       irq = it->options[1];
+       if (irq) {
+               printk("( irq = %u )", irq);
+               if ((ret = comedi_request_irq(irq, rti800_interrupt, 0,
+                                       "rti800", dev)) < 0) {
+                       printk(" Failed to allocate IRQ\n");
                        return ret;
-               dev->irq=irq;
-       }else if(irq == 0){
+               }
+               dev->irq = irq;
+       } else {
                printk("( no irq )");
        }
 
        dev->board_name = this_board->name;
 
-       dev->n_subdevices=4;
-       if((ret=alloc_subdevices(dev))<0)
+       if ((ret = alloc_subdevices(dev, 4)) < 0)
                return ret;
-       if((ret=alloc_private(dev,sizeof(rti800_private)))<0)
+       if ((ret = alloc_private(dev, sizeof(rti800_private))) < 0)
                return ret;
-       
+
        devpriv->adc_mux = it->options[2];
        devpriv->adc_range = it->options[3];
        devpriv->adc_coding = it->options[4];
@@ -351,14 +361,15 @@ static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
        devpriv->dac0_coding = it->options[6];
        devpriv->dac1_range = it->options[7];
        devpriv->dac1_coding = it->options[8];
+       devpriv->muxgain_bits = -1;
 
-       s=dev->subdevices+0;
+       s = dev->subdevices + 0;
        /* ai subdevice */
-       s->type=COMEDI_SUBD_AI;
-       s->subdev_flags=SDF_READABLE;
-       s->n_chan=(devpriv->adc_mux? 16 : 8);
-       s->insn_read=rti800_ai_insn_read;
-       s->maxdata=0xfff;
+       s->type = COMEDI_SUBD_AI;
+       s->subdev_flags = SDF_READABLE | SDF_GROUND;
+       s->n_chan = (devpriv->adc_mux ? 16 : 8);
+       s->insn_read = rti800_ai_insn_read;
+       s->maxdata = 0xfff;
        switch (devpriv->adc_range) {
        case adc_bipolar10:
                s->range_table = &range_rti800_ai_10_bipolar;
@@ -372,15 +383,15 @@ static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
        }
 
        s++;
-       if (this_board->has_ao){
+       if (this_board->has_ao) {
                /* ao subdevice (only on rti815) */
-               s->type=COMEDI_SUBD_AO;
-               s->subdev_flags=SDF_WRITEABLE;
-               s->n_chan=2;
-               s->insn_read=rti800_ao_insn_read;
-               s->insn_write=rti800_ao_insn_write;
-               s->maxdata=0xfff;
-               s->range_table_list=devpriv->ao_range_type_list;
+               s->type = COMEDI_SUBD_AO;
+               s->subdev_flags = SDF_WRITABLE;
+               s->n_chan = 2;
+               s->insn_read = rti800_ao_insn_read;
+               s->insn_write = rti800_ao_insn_write;
+               s->maxdata = 0xfff;
+               s->range_table_list = devpriv->ao_range_type_list;
                switch (devpriv->dac0_range) {
                case dac_bipolar10:
                        devpriv->ao_range_type_list[0] = &range_bipolar10;
@@ -397,34 +408,33 @@ static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
                        devpriv->ao_range_type_list[1] = &range_unipolar10;
                        break;
                }
-       }else{
-               s->type=COMEDI_SUBD_UNUSED;
+       } else {
+               s->type = COMEDI_SUBD_UNUSED;
        }
 
        s++;
        /* di */
-       s->type=COMEDI_SUBD_DI;
-       s->subdev_flags=SDF_READABLE;
-       s->n_chan=8;
-       s->insn_bits=rti800_di_insn_bits;
-       s->maxdata=1;
-       s->range_table=&range_digital;
+       s->type = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan = 8;
+       s->insn_bits = rti800_di_insn_bits;
+       s->maxdata = 1;
+       s->range_table = &range_digital;
 
        s++;
        /* do */
-       s->type=COMEDI_SUBD_DO;
-       s->subdev_flags=SDF_WRITEABLE;
-       s->n_chan=8;
-       s->insn_bits=rti800_do_insn_bits;
-       s->maxdata=1;
-       s->range_table=&range_digital;
-
+       s->type = COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITABLE;
+       s->n_chan = 8;
+       s->insn_bits = rti800_do_insn_bits;
+       s->maxdata = 1;
+       s->range_table = &range_digital;
 
 /* don't yet know how to deal with counter/timers */
 #if 0
        s++;
        /* do */
-       s->type=COMEDI_SUBD_TIMER;
+       s->type = COMEDI_SUBD_TIMER;
 #endif
 
        printk("\n");
@@ -432,17 +442,15 @@ static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
        return 0;
 }
 
-
 static int rti800_detach(comedi_device * dev)
 {
        printk("comedi%d: rti800: remove\n", dev->minor);
 
-       if(dev->iobase)
+       if (dev->iobase)
                release_region(dev->iobase, RTI800_SIZE);
 
-       if(dev->irq)
-               free_irq(dev->irq,dev);
+       if (dev->irq)
+               comedi_free_irq(dev->irq, dev);
 
        return 0;
 }
-