/*
- 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
[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
#define RTI800_9513A_CNTRL 13
#define RTI800_9513A_STATUS 13
-
/*
* flags for CSR register
*/
#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 {
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;
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
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
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];
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;
}
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;
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");
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;
}
-