From: David Schleef <ds@schleef.org>
Date: Tue, 12 Dec 2000 04:58:07 +0000 (+0000)
Subject: update from frank
X-Git-Tag: r0_7_54~32
X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=1b8fde1aaf66ef427e93f2c543b8767351cabf4e;p=comedi.git

update from frank
---

diff --git a/comedi/drivers/das1800.c b/comedi/drivers/das1800.c
index a39142ff..9f8a78dc 100644
--- a/comedi/drivers/das1800.c
+++ b/comedi/drivers/das1800.c
@@ -23,37 +23,36 @@
 
 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;
-}