update from frank
authorDavid Schleef <ds@schleef.org>
Tue, 12 Dec 2000 04:58:07 +0000 (04:58 +0000)
committerDavid Schleef <ds@schleef.org>
Tue, 12 Dec 2000 04:58:07 +0000 (04:58 +0000)
comedi/drivers/das1800.c

index a39142ff1cc75bed84262110e2d8a62939ce0853..9f8a78dc5ab3bf267256bc971fadbd73ba724317 100644 (file)
 
 This driver supports the following Keithley boards:
 
-DAS-1801ST
-DAS-1802ST
-DAS-1802HR
+das-1701st/ao
+das-1702st/hr/ao
+das-1801st/hc/ao
+das-1802st/hr/hc/ao
 
 Options:
        [0] - base io address
-       [1] - irq (supports shareable interrupts)
+       [1] - irq (optional, required for timed or externally triggered conversions)
+       [2] - dma0 (optional)
+       [3] - dma1 (optional)
 
-cmd triggers supported:
-       start_src: TRIG_NOW
+irq can be omitted, although the cmd interface will not work without it.
+
+analog input cmd triggers supported:
+       start_src:      TRIG_NOW | TRIG_EXT
        scan_begin_src: TRIG_FOLLOW
        scan_end_src:   TRIG_COUNT
-       convert_src:    TRIG_TIMER
+       convert_src:    TRIG_TIMER | TRIG_EXT
        scan_end_src:   TRIG_COUNT
-       stop_src:       TRIG_END | TRIG_COUNT
+       stop_src:       TRIG_COUNT | TRIG_NONE
 
 TODO:
-       Support unipolar gains and single ended inputs
-       Support more cmd triggers
-       Speed up interrupt routine
-       Support dma transfers
-       Add support for cards' digital i/o
+       Support TRIG_TIMER and TRIG_EXT for scan_begin_src (burst mode)
        Add support for cards with analog out
+       Support waveform out for 'ao' cards
 
 NOTES:
 Only the DAS-1801ST has been tested by me.
+Unipolar and bipolar ranges cannot be mixed in the channel/gain list.
 
-BUGS:
-The DAS-1802ST cards are identified as DAS-1801ST cards, since the
-two boards have identical id bits.  The only difference between the
-cards are their gains.
 */
 
 #include <linux/kernel.h>
@@ -67,13 +66,16 @@ cards are their gains.
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/timer.h>
-#include <linux/comedidev.h>
 #include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/comedidev.h>
+#include "8253.h"
 
-#define DAS1800_SIZE           16
-#define HALFFIFO               512
+#define DAS1800_SIZE           16      //uses 16 io addresses
+#define HALF_FIFO               512    // 1024 sample fifo
+#define TIMER_BASE             200     // 5 Mhz master clock
 
-/* Registers for the das800 */
+/* Registers for the das1800 */
 #define DAS1800_FIFO            0x0
 #define DAS1800_QRAM            0x0
 #define DAS1800_SELECT          0x2
@@ -81,6 +83,9 @@ cards are their gains.
 #define DAS1800_CONTROL_A       0x4
 #define   FFEN                    0x1
 #define   CGEN                    0x4
+#define   CGSL                    0x8
+#define   TGEN                    0x10
+#define   TGSL                    0x20
 #define DAS1800_CONTROL_B       0x5
 #define   FIMD                    0x40
 #define DAS1800_CONTROL_C       0X6
@@ -91,6 +96,7 @@ cards are their gains.
 #define   UB                      0x80
 #define DAS1800_STATUS          0x7
 #define   INT                     0x1
+#define   DMATC                   0x2
 #define   OVF                     0x10
 #define   FHF                     0x20
 #define   FNE                     0x40
@@ -99,32 +105,118 @@ cards are their gains.
 #define DAS1800_COUNTER(a)        (0xc + a)
 #define DAS1800_COUNTER_CONTROL 0xf
 
+enum{das1701st, das1702st, das1702hr, das1701ao, das1702ao, das1801st, das1802st, das1802hr, das1801hc, das1802hc, das1801ao, das1802ao};
+
 typedef struct das1800_board_struct{
        char *name;
-       int ai_speed;
-       int resolution;
+       int ai_speed;   /* max conversion period in nanoseconds */
+       int resolution; /* bits of ai resolution */
+       int qram_len;   /* length of card's channel / gain queue */
+       int common;     /* supports AREF_COMMON flag */
+       int do_n_chan;  /* number of digital output channels */
 }das1800_board;
 
 das1800_board das1800_boards[] =
 {
        {
-               name:   "DAS-1801ST",
+               name:   "DAS-1701ST",
                /* Warning: the maximum conversion speeds listed below are
                 * not always achievable depending on board setup (see
                 * user manual.)
                 */
+               ai_speed:       6250,
+               resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:           "DAS-1702ST",
+               ai_speed:       6250,
+               resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:           "DAS-1702HR",
+               ai_speed:       20000,
+               resolution:     16,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:   "DAS-1701AO",
+               ai_speed:       6250,
+               resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:           "DAS-1702AO",
+               ai_speed:       6250,
+               resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:   "DAS-1801ST",
                ai_speed:       3000,
                resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
        },
        {
                name:           "DAS-1802ST",
                ai_speed:       3000,
                resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
        },
        {
                name:           "DAS-1802HR",
                ai_speed:       10000,
                resolution:     16,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:           "DAS-1801HC",
+               ai_speed:       3000,
+               resolution:     12,
+               qram_len:       64,
+               common: 0,
+               do_n_chan:      8,
+       },
+       {
+               name:           "DAS-1802HC",
+               ai_speed:       3000,
+               resolution:     12,
+               qram_len:       64,
+               common: 0,
+               do_n_chan:      8,
+       },
+       {
+               name:   "DAS-1801AO",
+               ai_speed:       3000,
+               resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
+       },
+       {
+               name:           "DAS-1802AO",
+               ai_speed:       3000,
+               resolution:     12,
+               qram_len:       256,
+               common: 1,
+               do_n_chan:      4,
        },
 };
 /*
@@ -135,62 +227,68 @@ das1800_board das1800_boards[] =
 typedef struct{
        unsigned long count;  /* number of data points left to be taken */
        int forever;  /* flag indicating whether we should take data forever */
-       unsigned short divisor1;        /* value to load into board's counter 1 for timed conversions */
-       unsigned short divisor2;        /* value to load into board's counter 2 for timed conversions */
+       unsigned int divisor1;  /* value to load into board's counter 1 for timed conversions */
+       unsigned int divisor2;  /* value to load into board's counter 2 for timed conversions */
+       int do_bits;    /* digital output bits */
+       int irq_dma_bits;       /* bits for control register b */
+       unsigned int dma0;      /* dma channels used */
+       unsigned int dma1;
+       unsigned int dma_current;       /* dma channel currently in use */
+       short *dma0_buf;        /* pointers to dma buffers */
+       short *dma1_buf;
+       short *dma_current_buf; /* pointer to dma buffer currently being used */
+       unsigned int dma_buf_size;      /* size in bytes of dma buffers */
+       int dual_dma;   /* flag that indicates whether we have dual dma */
 }das1800_private;
 
 #define devpriv ((das1800_private *)dev->private)
 
-static comedi_lrange range_das1801st_ai = {
-       4,
+static comedi_lrange range_das1801_ai = {
+       8,
        {
                RANGE( -5, 5 ),
                RANGE( -1, 1 ),
                RANGE( -0.1, 0.1 ),
                RANGE( -0.02, 0.02 ),
-/*             RANGE( 0, 5 ),
+               RANGE( 0, 5 ),
                RANGE( 0, 1 ),
                RANGE( 0, 0.1 ),
                RANGE( 0, 0.02 ),
-*/     }
-};
-
-static comedi_lrange range_das1802st_ai = {
-       4,
-       {
-               RANGE(-10, 10),
-               RANGE(-5, 5),
-               RANGE(-2.5, 2.5),
-               RANGE(-1.25, 1.25),
-/*             RANGE(0, 10),
-               RANGE(0, 5),
-               RANGE(0, 2.5),
-               RANGE(0, 1.25),
-*/     }
+       }
 };
 
-static comedi_lrange range_das1802hr_ai = {
-       4,
+static comedi_lrange range_das1802_ai = {
+       8,
        {
                RANGE(-10, 10),
                RANGE(-5, 5),
                RANGE(-2.5, 2.5),
                RANGE(-1.25, 1.25),
-/*             RANGE(0, 10),
+               RANGE(0, 10),
                RANGE(0, 5),
                RANGE(0, 2.5),
                RANGE(0, 1.25),
-*/     }
+       }
 };
 
 static comedi_lrange *das1800_range_lkup[] = {
-       &range_das1801st_ai,
-       &range_das1802st_ai,
-       &range_das1802hr_ai,
+       &range_das1801_ai,
+       &range_das1802_ai,
+       &range_das1802_ai,
+       &range_das1801_ai,
+       &range_das1802_ai,
+       &range_das1801_ai,
+       &range_das1802_ai,
+       &range_das1801_ai,
+       &range_das1802_ai,
+       &range_das1802_ai,
+       &range_das1801_ai,
+       &range_das1802_ai,
 };
 
 static int das1800_attach(comedi_device *dev, comedi_devconfig *it);
 static int das1800_detach(comedi_device *dev);
+static int das1800_recognize(char *name);
 static int das1800_cancel(comedi_device *dev, comedi_subdevice *s);
 
 comedi_driver driver_das1800={
@@ -198,46 +296,180 @@ comedi_driver driver_das1800={
        module:         THIS_MODULE,
        attach:         das1800_attach,
        detach:         das1800_detach,
+       recognize:              das1800_recognize,
 };
 
 static void das1800_interrupt(int irq, void *d, struct pt_regs *regs);
-void enable_das1800(comedi_device *dev);
+static void das1800_handle_dma(comedi_device *dev, comedi_subdevice *s);
+static void das1800_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s);
+static void das1800_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s);
 void disable_das1800(comedi_device *dev);
 static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd);
 static int das1800_ai_do_cmd(comedi_device *dev, comedi_subdevice *s);
 static int das1800_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);
+static int das1800_di_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);
+static int das1800_do_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);
 int das1800_probe(comedi_device *dev);
-int das1800_set_frequency( unsigned int period, comedi_device *dev);
-int das1800_load_counter(unsigned int counterNumber, int counterValue, comedi_device *dev);
-unsigned int das1800_find_divisors(unsigned int period, comedi_device *dev);
+int das1800_set_frequency(comedi_device *dev);
+int das1800_load_counter(unsigned int counterNumber, unsigned int counterValue, comedi_device *dev);
+
+static int das1800_recognize(char *name)
+{
+       if(!strcmp(name, "das-1701st"))
+               return das1701st;
+       if(!strcmp(name, "das-1702st"))
+               return das1702st;
+       if(!strcmp(name, "das-1702hr"))
+               return das1702hr;
+       if(!strcmp(name, "das-1701ao"))
+               return das1701ao;
+       if(!strcmp(name, "das-1702ao"))
+               return das1702ao;
+       if(!strcmp(name, "das-1801st") || !strcmp(name, "das1800"))
+               return das1801st;
+       if(!strcmp(name, "das-1802st"))
+               return das1802st;
+       if(!strcmp(name, "das-1802hr"))
+               return das1802hr;
+       if(!strcmp(name, "das-1801hc"))
+               return das1801hc;
+       if(!strcmp(name, "das-1802hc"))
+               return das1802hc;
+       if(!strcmp(name, "das-1801ao"))
+               return das1801ao;
+       if(!strcmp(name, "das-1802ao"))
+               return das1802ao;
 
-/* probes das-1800st/hr series board type - stupid boards have incomplete id
-       this isn't going to work */
+       return -1;
+}
+
+/* probes and checks das-1800 series board type
+ */
 int das1800_probe(comedi_device *dev)
 {
        int id;
-       id = inb(dev->iobase + DAS1800_DIGITAL) >> 4; /* get id bits */
+       id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0x7; /* get id bits */
        switch(id)
        {
-               case 0x7:
-                       printk(" Board model: DAS-1800ST series\n");
-                       return 0;
-                       break;
                case 0x3:
-                       printk(" Board model: DAS-1800ST-DA series\n");
-                       return 0;
+                       if(dev->board == das1801st)
+                       {
+                               printk(" Board model: DAS-1801ST-DA\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1802st)
+                       {
+                               printk(" Board model: DAS-1802ST-DA\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1701st)
+                       {
+                               printk(" Board model: DAS-1701ST-DA\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1702st)
+                       {
+                               printk(" Board model: DAS-1702ST-DA\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1800ST-DA series\n");
+                       return das1801st;
+                       break;
+               case 0x4:
+                       if(dev->board == das1802hr)
+                       {
+                               printk(" Board model: DAS-1802HR-DA\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1802HR-DA\n");
+                       if(dev->board == das1702hr)
+                       {
+                               printk(" Board model: DAS-1702HR-DA\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1802HR-DA\n");
+                       return das1802hr;
+                       break;
+               case 0x5:
+                       if(dev->board == das1801ao)
+                       {
+                               printk(" Board model: DAS-1801AO\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1802ao)
+                       {
+                               printk(" Board model: DAS-1802AO\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1701ao)
+                       {
+                               printk(" Board model: DAS-1701AO\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1702ao)
+                       {
+                               printk(" Board model: DAS-1702AO\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1800AO series\n");
+                       return das1801ao;
                        break;
                case 0x6:
-                       printk(" Board model: DAS-1802HR\n");
-                       return 2;
+                       if(dev->board == das1802hr)
+                       {
+                               printk(" Board model: DAS-1802HR\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1802HR\n");
+                       if(dev->board == das1702hr)
+                       {
+                               printk(" Board model: DAS-1702HR\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1702HR\n");
+                       return das1802hr;
                        break;
-               case 0x4:
-                       printk(" Board model: DAS-1802HR-DA\n");
-                       return 2;
+               case 0x7:
+                       if(dev->board == das1801st)
+                       {
+                               printk(" Board model: DAS-1801ST\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1802st)
+                       {
+                               printk(" Board model: DAS-1802ST\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1701st)
+                       {
+                               printk(" Board model: DAS-1701ST\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1702st)
+                       {
+                               printk(" Board model: DAS-1702ST\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1800ST series\n");
+                       return das1801st;
+                       break;
+               case 0x8:
+                       if(dev->board == das1801hc)
+                       {
+                               printk(" Board model: DAS-1801HC\n");
+                               return dev->board;
+                       }
+                       if(dev->board == das1802hc)
+                       {
+                               printk(" Board model: DAS-1802HC\n");
+                               return dev->board;
+                       }
+                       printk(" Board model (probed): DAS-1800HC series\n");
+                       return das1801hc;
                        break;
                default :
                        printk(" Board model: probe returned 0x%x (unknown)\n", id);
-                       return -1;
+                       return dev->board;
                        break;
        }
        return -1;
@@ -251,74 +483,246 @@ COMEDI_INITCLEANUP(driver_das1800);
 
 static void das1800_interrupt(int irq, void *d, struct pt_regs *regs)
 {
-       int i;          /* loop index */
-       int numPoints = HALFFIFO;       /* number of points to read */
-       int ret;
+       int status;
        comedi_device *dev = d;
        comedi_subdevice *s = dev->subdevices + 0;      /* analog input subdevice */
-       sampl_t dpnt;
 
-       ret = inb(dev->iobase + DAS1800_STATUS);
+       status = inb(dev->iobase + DAS1800_STATUS);
        /* if interrupt was not caused by das-1800 */
-       if(!(ret & INT))
+       if(!(status & INT))
+       {
                return;
-       if(ret & FHF)      /* if fifo half full */
+       } else if(devpriv->dma0)        /* if dma is enabled and generated the interrupt */
        {
-               /* if we only need some of the points */
-               if( devpriv->forever == 0 && devpriv->count < numPoints)
-                       numPoints = devpriv->count;
-               for( i = 0; i < numPoints; i++)
-               {
-                       /* write data point to buffer */
-                       if(s->buf_int_ptr + sizeof(sampl_t) > s->cur_trig.data_len )
-                       {
-                               s->buf_int_ptr = 0;
-                               comedi_eobuf(dev, s);
-                       }
-                       dpnt = inw(dev->iobase + DAS1800_FIFO);
-                       /* convert to offset binary */
-                       dpnt += 1 << (thisboard->resolution - 1); 
-                       *((sampl_t *)((void *)s->cur_trig.data + s->buf_int_ptr)) = dpnt;
-                       s->cur_chan++;
-                       if( s->cur_chan >= s->cur_chanlist_len )
-                       {
-                               s->cur_chan = 0;
-                               comedi_eos(dev, s);
-                       }
-                       s->buf_int_count += sizeof(sampl_t);
-                       s->buf_int_ptr += sizeof(sampl_t);
-                       if(devpriv->count > 0) devpriv->count--;
-               }
+               if(status & DMATC)
+                       das1800_handle_dma(dev, s);
+       } else if(status & FHF)
+       {
+               das1800_handle_fifo_half_full(dev, s);
+       } else if(status & FNE)
+       {
+               das1800_handle_fifo_not_empty(dev, s);
        }
-       comedi_bufcheck(dev,s);
-       if(ret & OVF)
+       comedi_bufcheck(dev, s);
+       /* if the card's fifo has overflowed */
+       if(status & OVF)
        {
                comedi_error(dev, "DAS1800 FIFO overflow");
-               das1800_cancel(dev, dev->subdevices + 0);
+               das1800_cancel(dev, s);
                comedi_error_done(dev, s);
                return;
        }
-       /* if there are more data points to collect */
-       if(devpriv->count > 0 || devpriv->forever == 1)
-               /* Re-enable card's interrupt */
-               outb(CVEN, dev->iobase + DAS1800_STATUS);
-       /* otherwise, stop taking data */
-       else
+       /* stop taking data if appropriate */
+       if(devpriv->count == 0 && devpriv->forever == 0)
        {
-               disable_das1800(dev);           /* diable hardware triggered conversions */
+               disable_das1800(dev);           /* diable hardware conversions */
                comedi_done(dev, s);
        }
+
+       return;
+}
+
+static void das1800_handle_dma(comedi_device *dev, comedi_subdevice *s)
+{
+       unsigned long flags;
+       int numPoints;
+       short dpnt;
+       short *buffer;
+       int unipolar;
+       int i;
+
+       if(get_dma_residue(devpriv->dma_current))
+               return;
+       numPoints = devpriv->count;
+       if(numPoints > devpriv->dma_buf_size / sizeof(sampl_t))
+               numPoints = devpriv->dma_buf_size / sizeof(sampl_t);
+       buffer = devpriv->dma_current_buf;
+       flags = claim_dma_lock();
+       disable_dma(devpriv->dma_current);
+       if(devpriv->dual_dma)
+       {
+               if(devpriv->dma_current == devpriv->dma0)
+               {
+                       devpriv->dma_current = devpriv->dma1;
+                       devpriv->dma_current_buf = devpriv->dma1_buf;
+               }
+               else
+               {
+                       devpriv->dma_current = devpriv->dma0;
+                       devpriv->dma_current_buf = devpriv->dma0_buf;
+               }
+       }
+       set_dma_addr(devpriv->dma_current, (unsigned int) devpriv->dma_current_buf);
+       if((devpriv->count - numPoints) * sizeof(short) > devpriv->dma_buf_size || devpriv->forever)
+               set_dma_count(devpriv->dma_current, devpriv->dma_buf_size);
+       else
+               set_dma_count(devpriv->dma_current, (devpriv->count - numPoints) * sizeof(short));
+
+       // if we are doing dual channel dma, enable the second channel immediately
+       if(devpriv->dual_dma)
+       {
+               enable_dma(devpriv->dma_current);
+               release_dma_lock(flags);
+       }
+
+       unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+
+       for( i = 0; i < numPoints; i++)
+       {
+               /* write data point to buffer */
+               if(s->buf_int_ptr + sizeof(sampl_t) > s->cur_trig.data_len )
+               {
+                       s->buf_int_ptr = 0;
+                       comedi_eobuf(dev, s);
+               }
+               dpnt = buffer[i];
+               /* convert to unsigned type if we are in a bipolar mode */
+               if(!unipolar);
+                       dpnt += 1 << (thisboard->resolution - 1);
+               *((sampl_t *)((void *)s->cur_trig.data + s->buf_int_ptr)) = dpnt;
+               s->cur_chan++;
+               if( s->cur_chan >= s->cur_chanlist_len )
+               {
+                       s->cur_chan = 0;
+                       comedi_eos(dev, s);
+               }
+               s->buf_int_count += sizeof(sampl_t);
+               s->buf_int_ptr += sizeof(sampl_t);
+               if(devpriv->count > 0) devpriv->count--;
+       }
+
+       // for single channel dma, re-enable after old data has been read
+       if(devpriv->dual_dma == 0)
+       {
+               enable_dma(devpriv->dma_current);
+               release_dma_lock(flags);
+       }
+
+       /* clear interrupt */
+       outb(FNE, dev->iobase + DAS1800_STATUS);
+
+       return;
+}
+
+static void das1800_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s)
+{
+       int i;          /* loop index */
+       int numPoints = 0;      /* number of points to read */
+       sampl_t dpnt;
+       int unipolar;
+
+       unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+
+       numPoints = HALF_FIFO;
+       /* if we only need some of the points */
+       if( devpriv->forever == 0 && devpriv->count < numPoints)
+               numPoints = devpriv->count;
+       for( i = 0; i < numPoints; i++)
+       {
+               /* write data point to buffer */
+               if(s->buf_int_ptr + sizeof(sampl_t) > s->cur_trig.data_len )
+               {
+                       s->buf_int_ptr = 0;
+                       comedi_eobuf(dev, s);
+               }
+               dpnt = inw(dev->iobase + DAS1800_FIFO);
+               /* convert to unsigned type if we are in a bipolar mode */
+               if(!unipolar);
+                       dpnt += 1 << (thisboard->resolution - 1);
+               *((sampl_t *)((void *)s->cur_trig.data + s->buf_int_ptr)) = dpnt;
+               s->cur_chan++;
+               if( s->cur_chan >= s->cur_chanlist_len )
+               {
+                       s->cur_chan = 0;
+                       comedi_eos(dev, s);
+               }
+               s->buf_int_count += sizeof(sampl_t);
+               s->buf_int_ptr += sizeof(sampl_t);
+               if(devpriv->count > 0) devpriv->count--;
+       }
+       /* clear interrupt */
+       outb(FNE, dev->iobase + DAS1800_STATUS);
+       // if there are just a few points left, switch to interrupt on end of conversion
+       if(devpriv->count < HALF_FIFO && devpriv->count > 0 && devpriv->forever == 0)
+       {
+               devpriv->irq_dma_bits &= ~FIMD; // interrupt fifo not empty
+               outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B);
+       }
+       return;
+}
+
+static void das1800_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s)
+{
+       sampl_t dpnt;
+       int unipolar;
+
+       unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+
+       while(inb(dev->iobase + DAS1800_STATUS) & FNE)
+       {
+               /* write data point to buffer */
+               if(s->buf_int_ptr + sizeof(sampl_t) > s->cur_trig.data_len )
+               {
+                       s->buf_int_ptr = 0;
+                       comedi_eobuf(dev, s);
+               }
+               dpnt = inw(dev->iobase + DAS1800_FIFO);
+               /* convert to unsigned type if we are in a bipolar mode */
+               if(!unipolar);
+                       dpnt += 1 << (thisboard->resolution - 1);
+               *((sampl_t *)((void *)s->cur_trig.data + s->buf_int_ptr)) = dpnt;
+               s->cur_chan++;
+               if( s->cur_chan >= s->cur_chanlist_len )
+               {
+                       s->cur_chan = 0;
+                       comedi_eos(dev, s);
+               }
+               s->buf_int_count += sizeof(sampl_t);
+               s->buf_int_ptr += sizeof(sampl_t);
+               if(devpriv->count > 0) devpriv->count--;
+               if(devpriv->count == 0 && devpriv->forever == 0)
+                       break;
+       }
+       /* clear interrupt */
+       outb(FNE, dev->iobase + DAS1800_STATUS);
+
        return;
 }
 
 static int das1800_attach(comedi_device *dev, comedi_devconfig *it)
 {
        comedi_subdevice *s;
-       unsigned char byte;
+       unsigned long flags;
        int iobase = it->options[0];
        int irq = it->options[1];
+       int dma0 = it->options[2];
+       int dma1 = it->options[3];
 
-       printk("comedi%d: das1800: io 0x%x, irq %i\n", dev->minor, iobase, irq);
+       /* allocate and initialize dev->private */
+       if(alloc_private(dev, sizeof(das1800_private)) < 0)
+               return -ENOMEM;
+
+       printk("comedi%d: das1800: io 0x%x", dev->minor, iobase);
+       if(irq)
+       {
+               printk(", irq %i", irq);
+               if(dma0)
+               {
+                       printk(", dma %i", dma0);
+                       if(dma1) printk(" and %i", dma1);
+               }
+       }
+       printk("\n");
+
+       dev->board = das1800_probe(dev);
+       if(dev->board < 0)
+       {
+               printk("unable to determine board type\n");
+               return -ENODEV;
+       }
+
+       dev->board_ptr = das1800_boards + dev->board;
+       dev->board_name = thisboard->name;
 
        /* check if io addresses are available */
        if(check_region(iobase, DAS1800_SIZE) < 0)
@@ -326,77 +730,137 @@ static int das1800_attach(comedi_device *dev, comedi_devconfig *it)
                printk("I/O port conflict\n");
                return -EIO;
        }
-       request_region(iobase, DAS1800_SIZE, "das1800");
+       request_region(iobase, DAS1800_SIZE, thisboard->name);
        dev->iobase = iobase;
        dev->iosize = DAS1800_SIZE;
 
        /* grab our IRQ */
-       byte = FIMD;    /* interrupt on half full fifo */
+       if(irq)
+       {
+               if(comedi_request_irq( irq, das1800_interrupt, 0, thisboard->name, dev ))
+               {
+                       printk( "unable to allocate irq %d\n", irq);
+                       return -EINVAL;
+               }
+       }
+       dev->irq = irq;
+
+       // set bits that tell card which irq to use
        switch(irq)
        {
                case 0:
                        break;
                case 3:
-                       byte |= 0x8;
+                       devpriv->irq_dma_bits |= 0x8;
                        break;
                case 5:
-                       byte |= 0x10;
+                       devpriv->irq_dma_bits |= 0x10;
                        break;
                case 7:
-                       byte |= 0x18;
+                       devpriv->irq_dma_bits |= 0x18;
                        break;
                case 10:
-                       byte |= 0x28;
+                       devpriv->irq_dma_bits |= 0x28;
                        break;
                case 11:
-                       byte |= 0x30;
+                       devpriv->irq_dma_bits |= 0x30;
                        break;
                case 15:
-                       byte |= 0x38;
+                       devpriv->irq_dma_bits |= 0x38;
                        break;
                default:
                        printk("irq out of range\n");
                        return -EINVAL;
                        break;
        }
-       outb(byte, dev->iobase + DAS1800_CONTROL_B); // tell board what irq to use
 
+//dma stuff
+       // need an irq to do dma
        if(irq)
        {
-               if(comedi_request_irq( irq, das1800_interrupt, SA_SHIRQ, "das1800", dev ))
+               if(dma0)
                {
-                       printk( "unable to allocate irq %d\n", irq);
-                       return -EINVAL;
+                       switch(dma0 | (dma1 << 4))
+                       {
+                               case 0x5:       // dma0 == 5
+                                       devpriv->irq_dma_bits |= 0x1;
+                                       break;
+                               case 0x6:       // dma0 == 6
+                                       devpriv->irq_dma_bits |= 0x2;
+                                       break;
+                               case 0x7:       // dma0 == 7
+                                       devpriv->irq_dma_bits |= 0x3;
+                                       break;
+                               case 0x65:      // dma0 == 5, dma1 == 6
+                                       devpriv->irq_dma_bits |= 0x5;
+                                       break;
+                               case 0x76:      // dma0 == 6, dma1 == 7
+                                       devpriv->irq_dma_bits |= 0x6;
+                                       break;
+                               case 0x57:      // dma0 == 7, dma1 == 5
+                                       devpriv->irq_dma_bits |= 0x7;
+                                       break;
+                               default:
+                                       printk("%s only supports dma channels 5 through 7\n"
+                                               "  Dual dma only allows the following combinations:\n"
+                                               "  dma 5,6 / 6,7 / or 7,5\n", thisboard->name);
+                                       return -EINVAL;
+                                       break;
+                       }
+                       if(request_dma(dma0, thisboard->name))
+                       {
+                               printk("failed to allocate dma channel %i\n", dma0);
+                               return -EINVAL;
+                       }
+                       devpriv->dma0 = dma0;
+                       devpriv->dma_current = dma0;
+                       if(dma1)
+                       {
+                               if(request_dma(dma1, thisboard->name))
+                               {
+                                       printk("failed to allocate dma channel %i\n", dma1);
+                                       return -EINVAL;
+                               }
+                               devpriv->dma1 = dma1;
+                               devpriv->dual_dma = 1;
+                       }
+                       devpriv->dma_buf_size = 0x1ff00;
+                       devpriv->dma0_buf = kmalloc(devpriv->dma_buf_size, GFP_BUFFER | GFP_DMA);
+                       if(devpriv->dma0_buf == 0)
+                               return -ENOMEM;
+                       devpriv->dma_current_buf = devpriv->dma0_buf;
+                       if(dma1)
+                       {
+                               devpriv->dma1_buf = kmalloc(devpriv->dma_buf_size, GFP_BUFFER | GFP_DMA);
+                               if(devpriv->dma1_buf == 0)
+                                       return -ENOMEM;
+                       }
+                       flags = claim_dma_lock();
+                       disable_dma(devpriv->dma0);
+                       clear_dma_ff(devpriv->dma0);
+                       set_dma_mode(devpriv->dma0, DMA_MODE_READ);
+                       if(dma1)
+                       {
+                               disable_dma(devpriv->dma1);
+                               clear_dma_ff(devpriv->dma1);
+                               set_dma_mode(devpriv->dma1, DMA_MODE_READ);
+                       }
+                       release_dma_lock(flags);
                }
        }
-       dev->irq = irq;
 
-       dev->board = das1800_probe(dev);
-       if(dev->board < 0)
-       {
-               printk("unable to determine board type\n");
-               return -ENODEV;
-       }
-
-       dev->board_ptr = das1800_boards + dev->board;
-       dev->board_name = thisboard->name;
-
-       /* allocate and initialize dev->private */
-       if(alloc_private(dev, sizeof(das1800_private)) < 0)
-               return -ENOMEM;
-       devpriv->count = 0;
-       devpriv->forever = 0;
-
-       dev->n_subdevices = 1;
+       dev->n_subdevices = 4;
        if(alloc_subdevices(dev) < 0)
                return -ENOMEM;
 
        /* analog input subdevice */
        s = dev->subdevices + 0;
        s->type = COMEDI_SUBD_AI;
-       s->subdev_flags = SDF_READABLE | SDF_DIFF;
-       s->n_chan = 256;
-       s->len_chanlist = 256;
+       s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
+       if(thisboard->common)
+               s->subdev_flags |= SDF_COMMON;
+       s->n_chan = thisboard->qram_len;
+       s->len_chanlist = thisboard->qram_len;
        s->maxdata = (1 << thisboard->resolution) - 1;
        s->range_table = das1800_range_lkup[dev->board];
        s->do_cmd = das1800_ai_do_cmd;
@@ -404,6 +868,28 @@ static int das1800_attach(comedi_device *dev, comedi_devconfig *it)
        s->insn_read = das1800_ai_rinsn;
        s->cancel = das1800_cancel;
 
+       /* analog out (TODO!)*/
+       s = dev->subdevices + 1;
+       s->type = COMEDI_SUBD_UNUSED;
+
+       /* di */
+       s = dev->subdevices + 2;
+       s->type = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan = 4;
+       s->maxdata = 1;
+       s->range_table = &range_digital;
+       s->insn_read = das1800_di_rinsn;
+
+       /* do */
+       s = dev->subdevices + 3;
+       s->type=COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITEABLE;
+       s->n_chan = thisboard->do_n_chan;
+       s->maxdata = 1;
+       s->range_table = &range_digital;
+       s->insn_write = das1800_do_winsn;
+
        return 0;
 };
 
@@ -413,15 +899,18 @@ static int das1800_detach(comedi_device *dev)
 
        /* only free stuff if it has been allocated by _attach */
        if(dev->iobase)
-       {
                release_region(dev->iobase, DAS1800_SIZE);
-               dev->iobase = 0;
-       }
        if(dev->irq)
-       {
                comedi_free_irq(dev->irq, dev);
-               dev->irq = 0;
-       }
+       if(devpriv->dma0)
+               free_dma(devpriv->dma0);
+       if(devpriv->dma0_buf)
+               kfree(devpriv->dma0_buf);
+       if(devpriv->dma1)
+               free_dma(devpriv->dma1);
+       if(devpriv->dma1_buf)
+               kfree(devpriv->dma1_buf);
+
        return 0;
 };
 
@@ -433,18 +922,13 @@ static int das1800_cancel(comedi_device *dev, comedi_subdevice *s)
        return 0;
 }
 
-/* enable_das1800 makes the card start taking hardware triggered conversions */
-void enable_das1800(comedi_device *dev)
-{
-       outb(CGEN | FFEN, dev->iobase + DAS1800_CONTROL_A);     /* enable fifo and hardware triggering */
-       outb(CVEN, dev->iobase + DAS1800_STATUS);       /* enable conversions */
-}
-
-/* disable_das1800 stops hardware triggered conversions */
 void disable_das1800(comedi_device *dev)
 {
        outb(0x0, dev->iobase + DAS1800_STATUS);        /* disable conversions */
        outb(0x0, dev->iobase + DAS1800_CONTROL_A);     /* disable and clear fifo and stop triggering */
+       outb(0x0, dev->iobase + DAS1800_CONTROL_B);     /* disable interrupts and dma */
+       if(devpriv->dma0) disable_dma(devpriv->dma0);
+       if(devpriv->dma1) disable_dma(devpriv->dma1);
 }
 
 static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
@@ -455,7 +939,7 @@ static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_c
        /* step 1: make sure trigger sources are trivially valid */
 
        tmp = cmd->start_src;
-       cmd->start_src &= TRIG_NOW;
+       cmd->start_src &= TRIG_NOW | TRIG_EXT;
        if(!cmd->start_src && tmp != cmd->start_src) err++;
 
        tmp = cmd->scan_begin_src;
@@ -463,7 +947,7 @@ static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_c
        if(!cmd->scan_begin_src && tmp != cmd->scan_begin_src) err++;
 
        tmp = cmd->convert_src;
-       cmd->convert_src &= TRIG_TIMER;
+       cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
        if(!cmd->convert_src && tmp != cmd->convert_src) err++;
 
        tmp = cmd->scan_end_src;
@@ -472,15 +956,17 @@ static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_c
 
        tmp=cmd->stop_src;
        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
-       if(!cmd->stop_src && tmp!=cmd->stop_src) err++;
+       if(!cmd->stop_src && tmp != cmd->stop_src) err++;
 
        if(err) return 1;
 
        /* step 2: make sure trigger sources are unique and mutually compatible */
 
-       if(cmd->start_src != TRIG_NOW) err++;
+       if(cmd->start_src != TRIG_NOW &&
+               cmd->start_src != TRIG_EXT) err++;
        if(cmd->scan_begin_src != TRIG_FOLLOW) err++;
-       if(cmd->convert_src != TRIG_TIMER) err++;
+       if(cmd->convert_src != TRIG_TIMER &&
+               cmd->convert_src != TRIG_EXT) err++;
        if(cmd->scan_end_src != TRIG_COUNT) err++;
        if(cmd->stop_src != TRIG_COUNT &&
                cmd->stop_src != TRIG_NONE) err++;
@@ -539,7 +1025,8 @@ static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_c
        if(cmd->convert_src == TRIG_TIMER)
        {
                tmp = cmd->convert_arg;
-               cmd->convert_arg = das1800_find_divisors(cmd->convert_arg, dev);
+               /* calculate counter values that give desired timing */
+               i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);
                if(tmp != cmd->convert_arg) err++;
        }
 
@@ -551,6 +1038,10 @@ static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_c
 static int das1800_ai_do_cmd(comedi_device *dev, comedi_subdevice *s)
 {
        int i, n, chan_range;
+       int aref;
+       int conv_flags;
+       int control_a;
+       int lock_flags;
 
        if(!dev->irq)
        {
@@ -565,65 +1056,131 @@ static int das1800_ai_do_cmd(comedi_device *dev, comedi_subdevice *s)
        outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS);        /*set QRAM address start */
        for(i = 0; i < n; i++)  /* make channel / gain list */
        {
-               chan_range = CR_CHAN(s->cmd.chanlist[i]) | (CR_RANGE(s->cmd.chanlist[i]) << 8);
+               /* mask off unipolar/bipolar bit from range */
+               chan_range = CR_CHAN(s->cmd.chanlist[i]) | ((CR_RANGE(s->cmd.chanlist[i]) & 0x3) << 8);
                outw(chan_range, dev->iobase + DAS1800_QRAM);
        }
        outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS);        /*finish write to QRAM */
        outb(0x0, dev->iobase + DAS1800_SELECT);        /* select ADC for baseAddress + 0x0 */
 
+       /* enable auto channel scan, send interrupts on end of conversion,
+        * set clock source to internal or external, select analog reference,
+        * select unipolar / bipolar
+        */
+       aref = CR_AREF(s->cmd.chanlist[0]);
+       conv_flags = UQEN;
+       if(aref != AREF_DIFF)
+               conv_flags |= SD;
+       if(aref == AREF_COMMON)
+               conv_flags |= CMEN;
+       /* if a unipolar range was selected */
+       if(CR_RANGE(s->cmd.chanlist[0]) & 0x4)
+               conv_flags |= UB;
+       switch(s->cmd.convert_src)
+       {
+               case TRIG_TIMER:
+                       /* trig on cascaded counters */
+                       outb(conv_flags | 0x1, dev->iobase + DAS1800_CONTROL_C);
+                       /* set conversion frequency */
+                       i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), &(s->cmd.convert_arg), s->cmd.flags & TRIG_ROUND_MASK);
+                       if(das1800_set_frequency(dev) < 0)
+                       {
+                               comedi_error(dev, "Error setting up counters");
+                               return -1;
+                       }
+                       break;
+               case TRIG_EXT:
+                       /* trig on falling edge */
+                       outb(conv_flags | 0x3, dev->iobase + DAS1800_CONTROL_C);
+                       break;
+               default:
+                       break;
+       }
+
        switch(s->cmd.stop_src)
        {
                case TRIG_COUNT:
                        devpriv->count = s->cmd.stop_arg;
                        devpriv->forever = 0;
+                       /* set interrupt mode */
+                       if(s->cmd.stop_arg < HALF_FIFO)
+                               devpriv->irq_dma_bits &= ~FIMD; // interrupt fifo not empty
+                       else
+                               devpriv->irq_dma_bits |= FIMD;  //interrupt fifo half full
                        break;
                case TRIG_NONE:
                        devpriv->forever = 1;
                        devpriv->count = 0;
+                       devpriv->irq_dma_bits |= FIMD;
                        break;
-               default :
+               default:
                        break;
        }
+       /* set FIMD bit in control register b */
+       outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B);
 
-       /* enable auto channel scan, send interrupts on end of conversion
-        * and set clock source to internal or external
-        */
-       switch(s->cmd.convert_src)
+       // enable fifo
+       control_a = FFEN;
+       switch(s->cmd.start_src)
        {
-               case TRIG_TIMER:
-                       /* differential, bipolar, pacer clocks are clocks 1 and 2 */
-                       outb(UQEN | 0x1, dev->iobase + DAS1800_CONTROL_C);
-                       /* set conversion frequency */
-                       if(das1800_set_frequency(s->cmd.convert_arg, dev) < 0)
-                       {
-                               comedi_error(dev, "Error setting up counters");
-                               return -1;
-                       }
+               case TRIG_EXT:
+                       control_a |= TGEN | CGSL;
                        break;
-/*             case TRIG_EXT:
+               case TRIG_NOW:
+                       control_a |= CGEN;
                        break;
-*/             default:
+               default:
                        break;
        }
 
-       enable_das1800(dev);
+       outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); // enable irq/dma
+       if(devpriv->dma0)
+       {
+               lock_flags = claim_dma_lock();
+               disable_dma(devpriv->dma0);
+               set_dma_addr(devpriv->dma0, (unsigned int) devpriv->dma0_buf);
+               if(devpriv->count * sizeof(short) > devpriv->dma_buf_size || devpriv->forever)
+                       set_dma_count(devpriv->dma0, devpriv->dma_buf_size);
+               else
+                       set_dma_count(devpriv->dma0, devpriv->count * sizeof(short));
+               devpriv->dma_current = devpriv->dma0;
+               devpriv->dma_current_buf = devpriv->dma0_buf;
+               enable_dma(devpriv->dma0);
+               release_dma_lock(lock_flags);
+       }
+       outb(control_a, dev->iobase + DAS1800_CONTROL_A);       /* enable fifo and triggering */
+       outb(CVEN, dev->iobase + DAS1800_STATUS);       /* enable conversions */
+
        return 0;
 }
 
 static int das1800_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data)
 {
        int i, n;
-       int chan, range, chan_range;
+       int chan, range, aref, chan_range;
        int timeout = 1000;
        short dpnt;
-
-       outb(UQEN, dev->iobase + DAS1800_CONTROL_C);    /* software conversion enabled */
+       int conv_flags = 0;
+
+       /* set up analog reference and unipolar / bipolar mode */
+       aref = CR_AREF(insn->chanspec);
+       conv_flags |= UQEN;
+       if(aref != AREF_DIFF)
+               conv_flags |= SD;
+       if(aref == AREF_COMMON)
+               conv_flags |= CMEN;
+       /* if a unipolar range was selected */
+       if(CR_RANGE(insn->chanspec) & 0x4)
+               conv_flags |= UB;
+
+       outb(conv_flags, dev->iobase + DAS1800_CONTROL_C);      /* software conversion enabled */
        outb(CVEN, dev->iobase + DAS1800_STATUS);       /* enable conversions */
        outb(0x0, dev->iobase + DAS1800_CONTROL_A);     /* reset fifo */
        outb(FFEN, dev->iobase + DAS1800_CONTROL_A);
 
 
-       chan = CR_CHAN(insn->chanspec) & 0xff;
+       chan = CR_CHAN(insn->chanspec);
+       /* mask of unipolar/bipolar bit from range */
        range = CR_RANGE(insn->chanspec) & 0x3;
        chan_range = chan | (range << 8);
        outb(0x1, dev->iobase + DAS1800_SELECT);        /* select QRAM for baseAddress + 0x0 */
@@ -648,24 +1205,48 @@ static int das1800_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn
                        comedi_error(dev, "timeout");
                        return -ETIME;
                }
-               /* shift data from true binary to offset binary */
                dpnt = inw(dev->iobase + DAS1800_FIFO);
-               dpnt += 1 << (thisboard->resolution - 1);
+               /* shift data to offset binary for bipolar ranges */
+               if((conv_flags & UB) == 0)
+                       dpnt += 1 << (thisboard->resolution - 1);
                data[n] = dpnt;
        }
 
        return n;
 }
 
+static int das1800_di_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data)
+{
+       int chan = CR_CHAN(insn->chanspec);
+       int ret;
 
-/* finds best values for cascaded counters to obtain desired frequency,
- * and loads counters with calculated values
- */
-int das1800_set_frequency(unsigned int period, comedi_device *dev)
+       ret = inb(dev->iobase + DAS1800_DIGITAL) & (1 << chan);
+       if(ret) data[0] = 1;
+       else data[0] = 0;
+
+       return 1;
+}
+
+static int das1800_do_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data)
+{
+       int chan = CR_CHAN(insn->chanspec);
+
+       // set channel to 1
+       if(data[0])
+               devpriv->do_bits |= (1 << chan);
+       // set channel to 0
+       else
+               devpriv->do_bits &= ~(1 << chan);
+       outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL);
+
+       return 1;
+}
+
+/* loads counters with divisor1, divisor2 from private structure */
+int das1800_set_frequency(comedi_device *dev)
 {
        int err = 0;
 
-       das1800_find_divisors(period, dev);
        if(das1800_load_counter(1, devpriv->divisor1, dev)) err++;
        if(das1800_load_counter(2, devpriv->divisor2, dev)) err++;
        if(err)
@@ -674,12 +1255,12 @@ int das1800_set_frequency(unsigned int period, comedi_device *dev)
        return 0;
 }
 
-int das1800_load_counter(unsigned int counterNumber, int counterValue, comedi_device *dev)
+int das1800_load_counter(unsigned int counterNumber, unsigned int counterValue, comedi_device *dev)
 {
        unsigned char byte;
 
        if(counterNumber > 2) return -1;
-       if(counterValue < 2 || counterValue > 0xffff) return -1;
+       if(counterValue == 1 || counterValue > 0xffff) return -1;
 
   byte = counterNumber << 6;
        byte = byte | 0x30;     // load low then high byte
@@ -691,34 +1272,3 @@ int das1800_load_counter(unsigned int counterNumber, int counterValue, comedi_de
        outb(byte, dev->iobase + DAS1800_COUNTER(counterNumber));
        return 0;
 }
-
-unsigned int das1800_find_divisors(unsigned int period, comedi_device *dev)
-{
-       int clock = 200;        // 5 MHz master clock
-       int temp, close;
-       unsigned short i, j;
-       unsigned int max, min;
-
-       if((devpriv->divisor1 * devpriv->divisor2 * clock) == period) return period;
-
-       max = (period / (2 * clock));
-       if(max > 0xffff)
-               max = 0xffff;
-       min = 2;
-       close = period;
-       for(i = min; i <= max; i++)
-       {
-               for(j = (period / (i * clock)); j <= (period / (i * clock)) + 1; j++)
-               {
-                       temp = period - clock * i * j;
-                       if(temp < 0) temp = -temp;
-                       if(temp < close && j >= min)
-                       {
-                               close = temp;
-                               devpriv->divisor1 = i; devpriv->divisor2 = j;
-                               if(close == 0) return period;
-                       }
-               }
-       }
-       return devpriv->divisor1 * devpriv->divisor2 * clock;
-}