changes from Chris Baugher
authorDavid Schleef <ds@schleef.org>
Mon, 18 Dec 2000 16:36:34 +0000 (16:36 +0000)
committerDavid Schleef <ds@schleef.org>
Mon, 18 Dec 2000 16:36:34 +0000 (16:36 +0000)
comedi/drivers/das16-new.c

index 49dbcea711f8be82d5ce185f9959bda01cacfd26..93a4853f0881a71c27fd7260d9b9189171872acc 100644 (file)
@@ -4,6 +4,7 @@
 
     COMEDI - Linux Control and Measurement Device Interface
     Copyright (C) 2000 David A. Schleef <ds@stm.lbl.gov>
+       Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -24,7 +25,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/comedidev.h>
+#include <comedi_module.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
 #define DAS16_STATUS           8
 #define   DAS16_EOC                    (1<<7)
 #define   DAS16_UB                     (1<<6)
-#define   DAS16_MUXbit                 (1<<5)
-#define   DAS16_INT                    (1<<4)
+#define   DAS16_MUXBIT                 (1<<5)
 #define   DAS16_INT                    (1<<4)
 #define DAS16_CONTROL          9
 #define   DAS16_INTE                   (1<<7)
 #define   DAS16_IRQ(x)                 ((x)<<4)
 #define   DAS16_DMA                    (1<<2)
-#define   DAS16_TS(x)                  ((x)<<0)
-#define DAS16_PACER            0x0a
+#define   DAS16_CTR2           0x03
+#define   DAS16_IP0                    0x02
+#define   DAS16_SOFT           0x00
+#define DAS16_PACER            0x0A
 #define   DAS16_CTR0                   (1<<1)
 #define   DAS16_TRIG0                  (1<<0)
-#define DAS16_GAIN             0x0b
+#define DAS16_GAIN             0x0B
+#define DAS16_CNTR0_DATA               0x0C
+#define DAS16_CNTR1_DATA               0x0D
+#define DAS16_CNTR2_DATA               0x0E
+#define DAS16_CNTR_CONTROL     0x0F
+#define   DAS16_TERM_CNT       0x00
+#define   DAS16_ONE_SHOT       0x02
+#define   DAS16_RATE_GEN       0x04
+#define   DAS16_CNTR_LSB_MSB   0x30
+#define   DAS16_CNTR0          0x00
+#define   DAS16_CNTR1          0x40
+#define   DAS16_CNTR2          0x80
 
 #define DAS1600_CONV           0x404
+#define   DAS1600_CONV_DISABLE 0x40
 #define DAS1600_BURST          0x405
 #define   DAS1600_BURST_VAL            0x40
 #define DAS1600_ENABLE         0x406
 #define   DAS1600_ENABLE_VAL           0x40
-#define DAS1600_BURST_STATUS   0x407
-#define   DAS1600_BME                  (1<<7)
-#define   DAS1600_ME                   (1<<6)
-#define   DAS1600_CD                   (1<<5)
-#define   DAS1600_WS                   (1<<1)
-#define   DAS1600_CLK                  (1<<0)
-
+#define DAS1600_STATUS_B       0x407
+#define   DAS1600_BME          0x40
+#define   DAS1600_ME           0x20
+#define   DAS1600_CD                   0x10
+#define   DAS1600_WS                   0x02
+#define   DAS1600_CLK_10MHZ            0x01
 
+#define DAS16_SLOWEST_TIMER            429000000000
+#define DAS16_FASTEST_TIMER            10000
 
 static comedi_lrange range_das1x01_bip = { 4, {
        BIP_RANGE( 10 ),
@@ -211,6 +226,17 @@ static int das16_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *in
 static int das16_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
 static int das16_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
 
+static int das16_cmd_test(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd);
+static int das16_cmd_exec(comedi_device *dev,comedi_subdevice *s);
+static int das16_cancel(comedi_device *dev, comedi_subdevice *s);
+
+static void das16_reset(comedi_device *dev);
+static void das16_interrupt(int irq, void *d, struct pt_regs *regs);
+
+static float das16_set_pacer(comedi_device *dev, unsigned int ns);
+static int das1600_mode_detect(comedi_device *dev);
+static void reg_dump(comedi_device *dev);
+
 struct das16_board_struct{
        char            *name;
        void            *ai;
@@ -400,17 +426,165 @@ comedi_driver driver_das16={
 };
 
 
-#define TIMEOUT 1000
+#define DAS16_TIMEOUT 1000
 
 
 struct das16_private_struct {
        unsigned int    ai_unipolar;
        unsigned int    ai_singleended;
        unsigned int    clockbase;
+       unsigned char   control_state;
+       volatile unsigned char  cmd_go;
+       unsigned int    adc_count;
 };
 #define devpriv ((struct das16_private_struct *)(dev->private))
 #define thisboard ((struct das16_board_struct *)(dev->board_ptr))
 
+static int das16_cmd_test(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd)
+{
+       int err=0, tmp;
+       
+       /* make sure triggers are valid */
+       tmp=cmd->start_src;
+       cmd->start_src &= TRIG_NOW;
+       if(!cmd->start_src && tmp!=cmd->start_src)err++;
+
+       tmp=cmd->scan_begin_src;
+       cmd->scan_begin_src &= TRIG_FOLLOW|TRIG_TIMER;
+       if(!cmd->scan_begin_src && tmp!=cmd->scan_begin_src)err++;
+
+       /* XXX This must be TRIG_FOLLOW until I figure out a way to *
+        * time the individual conversions.                         */
+       tmp=cmd->convert_src;
+       //cmd->convert_src &= TRIG_TIMER;
+       cmd->convert_src &= TRIG_FOLLOW;
+       if(!cmd->convert_src && tmp!=cmd->convert_src)err++;
+
+       tmp=cmd->scan_end_src;
+       cmd->scan_end_src &= TRIG_COUNT;
+       if(!cmd->scan_end_src && tmp!=cmd->scan_end_src)err++;
+
+       tmp=cmd->stop_src;
+       cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
+       if(!cmd->stop_src && tmp!=cmd->stop_src)err++;
+
+       if(err)return 1;
+       
+       /* step 2: make sure trigger sources are unique and mutually compatible */
+       /* note that mutual compatiblity is not an issue here */
+       if(cmd->scan_begin_src!=TRIG_FOLLOW &&
+          cmd->scan_begin_src!=TRIG_EXT &&
+          cmd->scan_begin_src!=TRIG_TIMER)err++;
+       if(cmd->stop_src!=TRIG_COUNT &&
+          cmd->stop_src!=TRIG_NONE)err++;
+
+       if(err)return 2;
+       
+       /* step 3: make sure arguments are trivially compatible */
+       if(cmd->start_arg!=0){
+               cmd->start_arg=0;
+               err++;
+       }
+
+#if 0
+       if(cmd->scan_begin_src==TRIG_FOLLOW){
+               /* internal trigger */
+               if(cmd->scan_begin_arg!=0){
+                       cmd->scan_begin_arg=0;
+                       err++;
+               }
+       }else{
+               /* external trigger */
+               /* should be level/edge, hi/lo specification here */
+               if(cmd->scan_begin_arg!=0){
+                       cmd->scan_begin_arg=0;
+                       err++;
+               }
+       }
+#endif
+       
+       if(cmd->scan_begin_arg<DAS16_FASTEST_TIMER){
+               cmd->scan_begin_arg=DAS16_FASTEST_TIMER;
+               err++;
+       }
+
+       if(cmd->scan_begin_arg>DAS16_SLOWEST_TIMER){
+               cmd->scan_begin_arg=DAS16_SLOWEST_TIMER;
+               err++;
+       }
+
+       if(cmd->scan_end_arg!=cmd->chanlist_len){
+               cmd->scan_end_arg=cmd->chanlist_len;
+               err++;
+       }
+       
+       if(cmd->stop_src==TRIG_COUNT){
+               /* any count is allowed */
+       }else{
+               /* TRIG_NONE */
+               if(cmd->stop_arg!=0){
+                       cmd->stop_arg=0;
+                       err++;
+               }
+       }
+
+       if(err)return 3;
+       
+       return 0;
+}
+
+static int das16_cmd_exec(comedi_device *dev,comedi_subdevice *s)
+{
+       comedi_cmd *cmd = &s->cmd;
+       char byte;
+       float freq;
+       
+       devpriv->adc_count = cmd->stop_arg*cmd->chanlist_len;
+       devpriv->cmd_go = 1;
+       
+       /* check if we are scanning multiple channels */
+       if(cmd->chanlist_len < 2) {     /* one channel */
+               byte = CR_CHAN(cmd->chanlist[0]);
+               outb(byte, dev->iobase+DAS16_MUX);
+       } else {        /* multiple channels */
+               byte = CR_CHAN(cmd->chanlist[0]) +
+                       (CR_CHAN(cmd->chanlist[cmd->chanlist_len-1]<<4));
+               outb(byte, dev->iobase+DAS16_MUX);
+       }
+
+       /* enable pacer clocked conversions */
+       devpriv->control_state |= DAS16_CTR2;
+       outb(devpriv->control_state,dev->iobase+DAS16_CONTROL);
+       
+       /* set counter mode and counts */
+       freq = das16_set_pacer(dev, cmd->scan_begin_arg);
+
+       printk("pacer frequency: %d\n", (int)freq);
+       /* enable counters */
+       outb(0x00,dev->iobase+DAS16_PACER);
+       /* clear interrupt bit */
+       outb(0x00,dev->iobase+DAS16_STATUS);
+       /* enable interrupts */
+       devpriv->control_state |= DAS16_INTE;
+       outb(devpriv->control_state,dev->iobase+DAS16_CONTROL);
+
+       return 0;
+}
+
+static int das16_cancel(comedi_device *dev, comedi_subdevice *s)
+{
+       devpriv->cmd_go = 0;
+       
+       return 0;
+}
+
+static void das16_reset(comedi_device *dev)
+{
+       outb(0,dev->iobase+DAS16_STATUS);
+       outb(0,dev->iobase+DAS16_CONTROL);
+       outb(0,dev->iobase+DAS16_PACER);
+       outb(0,dev->iobase+DAS16_CNTR_CONTROL);
+}
 
 static int das16_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
 {
@@ -436,16 +610,16 @@ static int das16_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *in
 
        /* How long should we wait for MUX to settle? */
        //udelay(5);
-
+       
        for(n=0;n<insn->n;n++){
                /* trigger conversion */
                outb_p(0,dev->iobase+DAS16_TRIG);
 
-               for(i=0;i<TIMEOUT;i++){
+               for(i=0;i<DAS16_TIMEOUT;i++){
                        if(!(inb(DAS16_STATUS)&DAS16_EOC))
                                break;
                }
-               if(i==TIMEOUT){
+               if(i==DAS16_TIMEOUT){
                        rt_printk("das16: timeout\n");
                        return -ETIME;
                }
@@ -477,21 +651,21 @@ static int das16_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *in
 
 static int das16_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
 {
-       int n;
+       int i;
        int lsb,msb;
        int chan;
 
-       if(thisboard->ao_nbits==12){
-               lsb=(data[0]<<4)&0xff;
-               msb=(data[0]>>4)&0xff;
-       }else{
-               lsb=data[0]&0xff;
-               msb=(data[0]>>8)&0xff;
-       }
-
        chan=CR_CHAN(insn->chanspec);
 
-       for(n=0;n<insn->n;n++){
+       for(i=0;i<insn->n;i++){
+               if(thisboard->ao_nbits==12){
+                       lsb=(data[i]<<4)&0xff;
+                       msb=(data[i]>>4)&0xff;
+               }else{
+                       lsb=data[i]&0xff;
+                       msb=(data[i]>>8)&0xff;
+               }
+
 #if 0
                outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
                outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
@@ -499,15 +673,167 @@ static int das16_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *in
                outb(lsb,dev->iobase+DAS16_AO_LSB(chan));
                outb(msb,dev->iobase+DAS16_AO_MSB(chan));
 #endif
-               /* XXX */
-               break;
        }
 
        return n;
 }
 
 
+static void das16_interrupt(int irq, void *d, struct pt_regs *regs)
+{
+       static int i, j;
+       static char lsb, msb;
+       
+       comedi_device *dev = d;
+       comedi_subdevice *s = dev->subdevices;
+       
+       if(devpriv->cmd_go)     {       /* Are we supposed to be here? */
+               /* check for missed conversions */
+       //      if( CR_CHAN(s->cur_chanlist[0]) != inb() )
+       //              printk("Channel MUX sync error\n");
+               
+               for(i=0;i<s->cur_chanlist_len;++i) {
+                       
+                       if(i) {         /* performing multiple conversions */                   
+                               outb(0x00, dev->iobase+DAS16_TRIG);     /* force a conversion */
+                       
+                               for(j=0;j<DAS16_TIMEOUT;++j)    /* wait until it's ready */
+                                       if( !(inb(dev->iobase+DAS16_STATUS)&DAS16_EOC) )
+                                               break;
+                               if(j==DAS16_TIMEOUT)
+                                       printk("das16 EOC timeout!!");
+                       }
+                       
+                       lsb = inb(dev->iobase+DAS16_AI_LSB);
+                       msb = inb(dev->iobase+DAS16_AI_MSB);
+                       
+                       /* all this just to put data into a buffer! */
+                       *(sampl_t *)(((void *)s->cur_trig.data)+s->buf_int_ptr) =
+                               (lsb>>4) + (msb<<4);
+               
+                       s->buf_int_ptr += sizeof(sampl_t);
+                       s->buf_int_count += sizeof(sampl_t);
+               
+                       if(s->buf_int_ptr >= s->cur_trig.data_len) {    /* buffer rollover */
+                               s->buf_int_ptr = 0;
+                               comedi_eobuf(dev, s);
+                       }
+               
+                       if( !(s->cmd.flags&TRIG_WAKE_EOS) )
+                               comedi_bufcheck(dev, s);        /* wakeup user's read() */
+               
+                       if(--devpriv->adc_count <= 0) {         /* end of acquisition */
+                               printk("End of acquisition\n");
+                               devpriv->cmd_go = 0;
+                               devpriv->control_state &= ~DAS16_INTE;
+                               outb(devpriv->control_state, dev->iobase+DAS16_CONTROL);
+                               comedi_done(dev, s);
+                               break;
+                       }
+
+               }       /* end of scan loop */
+               
+               comedi_eos(dev, s);
+               
+       } else {
+               printk("Acquisition canceled OR Stray interrupt!\n");
+               devpriv->control_state &= ~DAS16_INTE;
+               outb(devpriv->control_state, dev->iobase+DAS16_CONTROL);
+               comedi_error_done(dev, s);
+       }
+       
+       /* clear interrupt */
+       outb(0x00,dev->iobase+DAS16_STATUS);
+}
+
+/* This function takes a time in nanoseconds and sets the     *
+ * 2 pacer clocks to the closest frequency possible. It also  *
+ * returns the actual sampling rate.                          */
+static float das16_set_pacer(comedi_device *dev, unsigned int ns)
+{
+       short unsigned ctr1, ctr2;
+       unsigned int mask;
+       long product, error;
+
+       /* divide 10Mhz by frequency */
+       product = ( devpriv->clockbase/(1000000000.0/ns) ) + 0.5;
+       /* Now the job is to find two 16 bit numbers, that when multiplied
+          together are approximately equal to product.  Start by setting
+          one of them, ctr1 to 2 (minimum settable value) and increment until
+          the error is minimized and ctr2 is less than 32768.
+
+          NOTE: In Mode 2, a value of 1 is illegal! Therefore, crt1 and crt2
+          can never be 1.
+
+        */
+
+       printk("product: %ld\n", product);
+       ctr1 = product / 32768;
+       if (ctr1 < 2)
+               ctr1 = 2;
+       ctr2 = product / ctr1;
+       error = abs(product - (long) ctr2 * (long) ctr1);
+
+       while (error && ctr1 < 32768 && ctr2 > 1) {
+               ctr1++;
+               ctr2 = product / ctr1;
+               error = abs(product - (long) ctr2 * (long) ctr1);
+       }
+
+       /* the frequency is prime, add 1 to it */
+       if (error) {
+               product++;
+               ctr1 = product / 32768;
+               if (ctr1 < 2)
+                       ctr1 = 2;
+               ctr2 = product / ctr1;
+               error = abs(product - (long) ctr2 * (long) ctr1);
+
+               while (error && ctr1 < 32768 && ctr2 > 1) {
+                       ctr1++;
+                       ctr2 = product / ctr1;
+                       error = abs(product - (long) ctr2 * (long) ctr1);
+               }
+       }
+       /* we can't have ctr2 equal to 1, or system hangs */
+       if (ctr2 == 1) {
+               ctr2++;
+               ctr1 /= 2;
+       }
+       printk("ctr1: %d, ctr2: %d\n", ctr1, ctr2);
+       /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+       mask = DAS16_CNTR2 | DAS16_RATE_GEN | DAS16_CNTR_LSB_MSB;
+       outb(mask, dev->iobase+DAS16_CNTR_CONTROL);
+
+       outb(ctr2 & 0xFF , dev->iobase + DAS16_CNTR2_DATA);
+       outb(ctr2 >> 8, dev->iobase + DAS16_CNTR2_DATA);
+
+       mask = DAS16_CNTR1 | DAS16_RATE_GEN | DAS16_CNTR_LSB_MSB;
+       outb(mask, dev->iobase+DAS16_CNTR_CONTROL);
+
+       outb(ctr1 & 0xFF, dev->iobase + DAS16_CNTR1_DATA);
+       outb(ctr1 >> 8, dev->iobase + DAS16_CNTR1_DATA);
+       
+//     printk("SetPacerFreq: Pacer Register set to %#x\n", BoardData.pacerReg);
+       
+       return devpriv->clockbase / ((long) ctr1 * (long) ctr2) + 0.5;
+}
 
+static void reg_dump(comedi_device *dev)
+{
+       printk("********DAS1600 REGISTER DUMP********\n");
+       printk("DAS16_MUX: %x\n", inb(dev->iobase+DAS16_MUX) );
+       printk("DAS16_DIO: %x\n", inb(dev->iobase+DAS16_DIO) );
+       printk("DAS16_STATUS: %x\n", inb(dev->iobase+DAS16_STATUS) );
+       printk("DAS16_CONTROL: %x\n", inb(dev->iobase+DAS16_CONTROL) );
+       printk("DAS16_PACER: %x\n", inb(dev->iobase+DAS16_PACER) );
+       printk("DAS16_GAIN: %x\n", inb(dev->iobase+DAS16_GAIN) );
+       printk("DAS16_CNTR_CONTROL: %x\n", inb(dev->iobase+DAS16_CNTR_CONTROL) );
+       printk("DAS1600_CONV: %x\n", inb(dev->iobase+DAS1600_CONV) );
+       printk("DAS1600_BURST: %x\n", inb(dev->iobase+DAS1600_BURST) );
+       printk("DAS1600_ENABLE: %x\n", inb(dev->iobase+DAS1600_ENABLE) );
+       printk("DAS1600_STATUS_B: %x\n", inb(dev->iobase+DAS1600_STATUS_B) );   
+}
 
 static int detect_ao(comedi_device *dev)
 {
@@ -536,10 +862,9 @@ static int detect_ao(comedi_device *dev)
        return 0;
 }
 
-static int das16_probe(comedi_device *dev)
+static int das16_probe(comedi_device *dev, comedi_devconfig *it)
 {
        int status;
-       int burststatus;
        int diobits;
 
        /* status is available on all boards */
@@ -562,14 +887,19 @@ static int das16_probe(comedi_device *dev)
 
        diobits = inb(dev->iobase + DAS16_DIO) & 0xf0;
 
-printk("diobits 0x%02x",diobits);
+       printk(" diobits 0x%02x",diobits);
+
        switch(diobits){
        case 0x80:
                printk(" das16 or das16/f");
                /* only difference is speed, so not an issue yet */
+               //devpriv->clockbase = it->options[4];
+               devpriv->clockbase = 10000000;
                return das16_board_das16;
        case 0x00:
                printk(" das16jr or das16/330");
+               //devpriv->clockbase = it->options[4];
+               devpriv->clockbase = 10000000;
                /* the 330 has ao, 16jr does not */
 
                /* we can write the low 4 bits without updating DAC */
@@ -578,20 +908,38 @@ printk("diobits 0x%02x",diobits);
                }else{
                        return das16_board_das16jr;
                }
-
-               break;
+       case 0xC0:
+               printk(" das1600\n");
+               das1600_mode_detect(dev);
+               return das16_board_das1601_12;
+       case 0xE0:
+               printk(" das1400\n");
+               das1600_mode_detect(dev);
+               return das16_board_das1401_12;
        default:
-               printk(" unknown board");
+               printk(" unknown board\n");
                return -1;
-       case 0xc0:
-               printk(" das1600 or das1400");
-               break;
        }
+}
 
-       /* burststatus is available on 1600, 1400 */
-
-       burststatus = inb(dev->iobase + DAS1600_BURST_STATUS);
+static int das1600_mode_detect(comedi_device *dev)
+{
+       int status=0;
+       
+       status = inb(dev->iobase + DAS1600_STATUS_B);
+       
+       if(status & DAS1600_CLK_10MHZ) {
+               devpriv->clockbase = 10000000;
+               printk(" 10MHz pacer clock\n");
+       } else {
+               devpriv->clockbase = 1000000;
+               printk(" 1MHz pacer clock\n");
+       }
 
+       /* enable das1400/1600 mode */
+//     outb(DAS1600_ENABLE_VAL, dev->iobase+DAS1600_ENABLE);
+#ifdef DETECT  
+       /* burststatus is available on 1600, 1400 */
        if((burststatus & 0xfc)==0x10){
                /* true for 1400, 1600 */
        }
@@ -602,8 +950,6 @@ printk("diobits 0x%02x",diobits);
                devpriv->clockbase = 1000;
        }
 
-       outb(DAS1600_ENABLE_VAL,dev->iobase+DAS1600_ENABLE);
-
        if(detect_ao(dev)){
                printk("das1600 series\n");
                return das16_board_das1601_12;
@@ -611,7 +957,9 @@ printk("diobits 0x%02x",diobits);
                printk("das1400 series\n");
                return das16_board_das1401_12;
        }
+#endif
 
+       return 0;
 }
 
 
@@ -633,12 +981,14 @@ static int das16_recognize(char *name)
  * Options list:
  *   0  I/O base
  *   1  IRQ
+ *   2  DMA
+ *   3  Clock speed
  */
 
 static int das16_attach(comedi_device *dev, comedi_devconfig *it)
 {
        comedi_subdevice *s;
-       int ret;
+       int ret, irq;
 
        dev->iobase = it->options[0];
 
@@ -647,25 +997,32 @@ static int das16_attach(comedi_device *dev, comedi_devconfig *it)
        if((ret=alloc_private(dev,sizeof(struct das16_private_struct)))<0)
                return ret;
 
-       dev->board = das16_probe(dev);
+       dev->board = das16_probe(dev, it);
 
        dev->board_ptr = das16_boards + dev->board;
        dev->board_name = thisboard->name;
+       
 
        if(thisboard->size<0x400){
-               printk(" 0x%04x-0x%04x",
-                       dev->iobase,dev->iobase+thisboard->size);
+               printk(" 0x%04x-0x%04x\n",
+                          dev->iobase,dev->iobase+thisboard->size);
                if(check_region(dev->iobase,thisboard->size)<0){
                        printk(" I/O port conflict\n");
                        return -EIO;
                }
        }else{
-               printk(" 0x%04x-0x%04x 0x%04x-0x%04x",
-                       dev->iobase,dev->iobase+0x0f,
-                       dev->iobase+0x400,dev->iobase+(thisboard->size&0x3ff));
-               if(check_region(dev->iobase,0x10)<0 ||
-                  check_region(dev->iobase+0x400,thisboard->size&0x3ff)<0){
-                       printk(" I/O port conflict\n");
+               printk(" 0x%04x-0x%04x 0x%04x-0x%04x\n",
+                          dev->iobase,dev->iobase+0x0f,
+                          dev->iobase+0x400,dev->iobase+0x400+(thisboard->size&0x3ff));
+               if(check_region(dev->iobase,0x10) < 0) {
+                       printk(" I/O port conflict:  0x%04x-0x%04x\n",
+                                  dev->iobase,dev->iobase+0x0f);
+                       return -EIO;
+               }
+               if(check_region(dev->iobase+0x400,thisboard->size&0x3ff)<0){
+                       printk(" I/O port conflict:  0x%04x-0x%04x\n",
+                                  dev->iobase+0x400,
+                                  dev->iobase+0x400+(thisboard->size&0x3ff));
                        return -EIO;
                }
        }
@@ -678,9 +1035,20 @@ static int das16_attach(comedi_device *dev, comedi_devconfig *it)
                request_region(dev->iobase,thisboard->size,"das16");
        }else{
                request_region(dev->iobase,0x10,"das16");
-               request_region(dev->iobase,thisboard->size&0x3ff,"das16");
+               request_region(dev->iobase+0x400,thisboard->size&0x3ff,"das16");
        }
 
+       /* now for the irq */
+       irq=it->options[1];
+       if(irq>0){
+               if((ret=request_irq(irq,das16_interrupt,SA_INTERRUPT,"das16",dev))<0)
+                       return ret;
+               dev->irq=irq;
+               printk(" ( irq = %d )\n",irq);
+       } else if(irq == 0){
+               printk(" ( no irq )\n");
+       }
+       
        s=dev->subdevices+0;
        /* ai */
        if(thisboard->ai){
@@ -693,6 +1061,7 @@ static int das16_attach(comedi_device *dev, comedi_devconfig *it)
                        s->n_chan = 8;
                        s->subdev_flags |= SDF_DIFF;
                }
+               s->len_chanlist = 16;
                s->maxdata = (1<<thisboard->ai_nbits)-1;
                if(devpriv->ai_unipolar){
                        s->range_table = das16_ai_uni_lranges[thisboard->ai_pg];
@@ -700,6 +1069,10 @@ static int das16_attach(comedi_device *dev, comedi_devconfig *it)
                        s->range_table = das16_ai_bip_lranges[thisboard->ai_pg];
                }
                s->insn_read = thisboard->ai;
+               s->do_cmdtest = das16_cmd_test;
+               s->do_cmd = das16_cmd_exec;
+               s->cancel = das16_cancel;
+               s->cmd.flags |= TRIG_WAKE_EOS;
        }else{
                s->type=COMEDI_SUBD_UNUSED;
        }
@@ -752,8 +1125,10 @@ static int das16_attach(comedi_device *dev, comedi_devconfig *it)
                s->type = COMEDI_SUBD_UNUSED;
        }
 
-       outb(DAS16_IRQ(dev->irq),dev->iobase+DAS16_CONTROL);
-       outb(0,DAS16_PACER);
+       das16_reset(dev);
+       /* set the interrupt level,enable pacer clock */
+       devpriv->control_state = DAS16_IRQ(dev->irq);
+       outb(devpriv->control_state,dev->iobase+DAS16_CONTROL);
 
        return 0;
 }
@@ -761,7 +1136,20 @@ static int das16_attach(comedi_device *dev, comedi_devconfig *it)
 
 static int das16_detach(comedi_device *dev)
 {
-
+       printk("comedi%d: das16: remove\n", dev->minor);
+       
+       das16_reset(dev);
+       
+       if(dev->irq)
+               free_irq(dev->irq, dev);
+       
+       if(thisboard->size<0x400){
+               release_region(dev->iobase,thisboard->size);
+       }else{
+               release_region(dev->iobase,0x10);
+               release_region(dev->iobase+0x400,thisboard->size&0x3ff);
+       }
+       
        return 0;
 }