enum{das1701st, das1701st_da, das1702st, das1702st_da, das1702hr, das1702hr_da, das1701ao, das1702ao, das1801st, das1801st_da, das1802st, das1802st_da, das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao};
+static int das1800_attach(comedi_device *dev, comedi_devconfig *it);
+static int das1800_detach(comedi_device *dev);
+static int das1800_recognize(char *name);
+int das1800_probe(comedi_device *dev);
+static int das1800_cancel(comedi_device *dev, comedi_subdevice *s);
+static void das1800_interrupt(int irq, void *d, struct pt_regs *regs);
+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);
+inline void write_to_buffer(comedi_device *dev, comedi_subdevice *s, sampl_t
+data_point); 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_ao_winsn(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_set_frequency(comedi_device *dev);
+int das1800_load_counter(comedi_device *dev, unsigned int counterNumber, unsigned int counterValue, unsigned int mode);
+unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode);
+
typedef struct das1800_board_struct{
char *name;
int ai_speed; /* max conversion period in nanoseconds */
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 */
int iobase2; /* secondary io address used for analog out on 'ao' boards */
short ao_update_bits; /* remembers the last write to the 'update' dac
*/ }das1800_private;
&range_das1802_ai,
};
-// analog output ranges
+// analog out range for boards with basic analog out
static comedi_lrange range_ao_1 = {
1,
{
}
};
+// analog out range for 'ao' boards
+/*
static comedi_lrange range_ao_2 = {
2,
{
RANGE(-5, 5),
}
};
-
-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={
driver_name: "das1800",
recognize: das1800_recognize,
};
-static void das1800_interrupt(int irq, void *d, struct pt_regs *regs);
-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 write_to_buffer(comedi_device *dev, comedi_subdevice *s, sampl_t data_point);
-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_ao_winsn(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(comedi_device *dev);
-int das1800_load_counter(comedi_device *dev, unsigned int counterNumber, unsigned int counterValue, unsigned int mode);
-unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode);
-
-static int das1800_recognize(char *name)
-{
- if(!strcmp(name, "das-1701st"))
- return das1701st;
- if(!strcmp(name, "das-1701st-da"))
- return das1701st_da;
- if(!strcmp(name, "das-1702st"))
- return das1702st;
- if(!strcmp(name, "das-1702st-da"))
- return das1702st_da;
- if(!strcmp(name, "das-1702hr"))
- return das1702hr;
- if(!strcmp(name, "das-1702hr-da"))
- return das1702hr_da;
- if(!strcmp(name, "das-1701ao"))
- return das1701ao;
- if(!strcmp(name, "das-1702ao"))
- return das1702ao;
- if(!strcmp(name, "das-1801st"))
- return das1801st;
- if(!strcmp(name, "das-1801st-da"))
- return das1801st_da;
- if(!strcmp(name, "das-1802st"))
- return das1802st;
- if(!strcmp(name, "das-1802st-da"))
- return das1802st_da;
- if(!strcmp(name, "das-1802hr"))
- return das1802hr;
- if(!strcmp(name, "das-1802hr-da"))
- return das1802hr_da;
- 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;
-
- 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) & 0x7; /* get id bits */
- switch(id)
- {
- // das-1800st-da
- case 0x3:
- if(dev->board == das1801st_da || dev->board == das1802st_da ||
- dev->board == das1701st_da || dev->board == das1702st_da)
- {
- printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
- return dev->board;
- }
- printk(" Board model (probed, not recommended): DAS-1800ST-DA series\n");
- return das1801st;
- break;
- // das-1800hr-da
- case 0x4:
- if(dev->board == das1802hr_da || dev->board == das1702hr_da)
- {
- printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
- return dev->board;
- }
- printk(" Board model (probed, not recommended): DAS-1802HR-DA\n");
- return das1802hr;
- break;
- case 0x5:
- if(dev->board == das1801ao || dev->board == das1802ao ||
- dev->board == das1701ao || dev->board == das1702ao)
- {
- printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
- return dev->board;
- }
- printk(" Board model (probed, not recommended): DAS-1800AO series\n");
- return das1801ao;
- break;
- case 0x6:
- if(dev->board == das1802hr || dev->board == das1702hr)
- {
- printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
- return dev->board;
- }
- printk(" Board model (probed, not recommended): DAS-1802HR\n");
- return das1802hr;
- break;
- case 0x7:
- if(dev->board == das1801st || dev->board == das1802st ||
- dev->board == das1701st || dev->board == das1702st)
- {
- printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
- return dev->board;
- }
- printk(" Board model (probed, not recommended): DAS-1800ST series\n");
- return das1801st;
- break;
- case 0x8:
- if(dev->board == das1801hc || dev->board == das1802hc)
- {
- printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
- return dev->board;
- }
- printk(" Board model (probed, not recommended): DAS-1800HC series\n");
- return das1801hc;
- break;
- default :
- printk(" Board model: probe returned 0x%x (unknown)\n", id);
- return dev->board;
- break;
- }
- return -1;
-}
-
/*
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
COMEDI_INITCLEANUP(driver_das1800);
-static void das1800_interrupt(int irq, void *d, struct pt_regs *regs)
-{
- int status;
- comedi_device *dev = d;
- comedi_subdevice *s = dev->subdevices + 0; /* analog input subdevice */
-
- status = inb(dev->iobase + DAS1800_STATUS);
- /* if interrupt was not caused by das-1800 */
- if(!(status & INT))
- {
- return;
- } else if(devpriv->dma0) /* if dma is enabled and generated the interrupt */
- {
- // dma buffer full or about-triggering (stop_src == TRIG_EXT)
- if(status & (DMATC | CT0TC))
- 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 the card's fifo has overflowed */
- if(status & OVF)
- {
- comedi_error(dev, "DAS1800 FIFO overflow");
- das1800_cancel(dev, s);
- comedi_error_done(dev, s);
- return;
- }
- /* stop taking data if appropriate */
- if(devpriv->count == 0 && devpriv->forever == 0)
- {
- disable_das1800(dev); /* disable hardware conversions */
- comedi_done(dev, s);
- }
-
- return;
-}
-
-static void das1800_handle_dma(comedi_device *dev, comedi_subdevice *s)
+static int das1800_attach(comedi_device *dev, comedi_devconfig *it)
{
+ comedi_subdevice *s;
unsigned long flags;
- int numPoints, maxPoints;
- short dpnt;
- short *buffer;
- int unipolar;
- int i;
+ int iobase = it->options[0];
+ int irq = it->options[1];
+ int dma0 = it->options[2];
+ int dma1 = it->options[3];
+ int iobase2;
- flags = claim_dma_lock();
- disable_dma(devpriv->dma_current);
- // figure out how many points to read
- if(devpriv->forever)
- numPoints = devpriv->dma_buf_size / sizeof(short);
- else
- numPoints = devpriv->count;
- maxPoints = (devpriv->dma_buf_size - get_dma_residue(devpriv->dma_current)) / sizeof(short);
- if(numPoints > maxPoints)
- numPoints = maxPoints;
- buffer = devpriv->dma_current_buf;
- if(devpriv->dual_dma)
+ /* 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)
{
- if(devpriv->dma_current == devpriv->dma0)
- {
- devpriv->dma_current = devpriv->dma1;
- devpriv->dma_current_buf = devpriv->dma1_buf;
- }
- else
+ printk(", irq %i", irq);
+ if(dma0)
{
- devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->dma0_buf;
+ printk(", dma %i", dma0);
+ if(dma1) printk(" and %i", dma1);
}
}
- 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));
+ printk("\n");
- // if we are doing dual channel dma, enable the second channel immediately
- if(devpriv->dual_dma)
+ if(iobase == 0)
{
- enable_dma(devpriv->dma_current);
- release_dma_lock(flags);
+ printk("io base address required for das1800\n");
+ return -EINVAL;
}
- /* see if card is using a unipolar or bipolar range */
- unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
-
- for( i = 0; i < numPoints; i++)
+ dev->board = das1800_probe(dev);
+ if(dev->board < 0)
{
- /* write data point to comedi buffer */
- dpnt = buffer[i];
- /* convert to unsigned type if we are in a bipolar mode */
- if(!unipolar);
- dpnt += 1 << (thisboard->resolution - 1);
- write_to_buffer(dev, s, dpnt);
- 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 */
- dpnt = inw(dev->iobase + DAS1800_FIFO);
- /* convert to unsigned type if we are in a bipolar mode */
- if(!unipolar);
- dpnt += 1 << (thisboard->resolution - 1);
- write_to_buffer(dev, s, dpnt);
- 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)
- {
- dpnt = inw(dev->iobase + DAS1800_FIFO);
- /* convert to unsigned type if we are in a bipolar mode */
- if(!unipolar);
- dpnt += 1 << (thisboard->resolution - 1);
- write_to_buffer(dev, s, dpnt);
- if(devpriv->count > 0) devpriv->count--;
- if(devpriv->count == 0 && devpriv->forever == 0)
- break;
- }
- /* clear interrupt */
- outb(FNE, dev->iobase + DAS1800_STATUS);
-
- return;
-}
-
-/* utility function used by das1800 interrupt service routines, really
- * should be inline
- */
-void write_to_buffer(comedi_device *dev, comedi_subdevice *s, sampl_t data_point)
-{
- if(s->buf_int_ptr >= s->cur_trig.data_len )
- {
- s->buf_int_ptr = 0;
- comedi_eobuf(dev, s);
- }
- *((sampl_t *)((void *)s->cur_trig.data + s->buf_int_ptr)) = data_point;
- 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);
-}
-
-static int das1800_attach(comedi_device *dev, comedi_devconfig *it)
-{
- comedi_subdevice *s;
- unsigned long flags;
- int iobase = it->options[0];
- int irq = it->options[1];
- int dma0 = it->options[2];
- int dma1 = it->options[3];
- int iobase2;
-
- /* 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");
-
- if(iobase == 0)
- {
- printk("io base address required for das1800\n");
- return -EINVAL;
- }
-
- dev->board = das1800_probe(dev);
- if(dev->board < 0)
- {
- printk("unable to determine board type\n");
- return -ENODEV;
+ printk("unable to determine board type\n");
+ return -ENODEV;
}
dev->board_ptr = das1800_boards + dev->board;
iobase2, iobase2 + DAS1800_SIZE);
return -EIO;
}
+ request_region(iobase2, DAS1800_SIZE, thisboard->name);
devpriv->iobase2 = iobase2;
}
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);
}
}
- dev->n_subdevices = 4;
- if(alloc_subdevices(dev) < 0)
- return -ENOMEM;
+ 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 | 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_ai_range_lkup[dev->board];
+ s->do_cmd = das1800_ai_do_cmd;
+ s->do_cmdtest = das1800_ai_do_cmdtest;
+ s->insn_read = das1800_ai_rinsn;
+ s->cancel = das1800_cancel;
+
+ /* analog out */
+ s = dev->subdevices + 1;
+ if(thisboard->ao_ability == 1)
+ {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = thisboard->ao_n_chan;
+ s->maxdata = (1 << thisboard->resolution) - 1;
+ s->range_table = &range_ao_1;
+ s->insn_write = das1800_ao_winsn;
+ }
+ else
+ {
+ 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;
+
+ disable_das1800(dev);
+
+ // initialize digital out channels
+ outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL);
+
+ // initialize analog out channels
+ if(thisboard->ao_ability == 1)
+ {
+ // select 'update' dac channel for baseAddress + 0x0
+ outb(DAC(thisboard->ao_n_chan - 1), dev->iobase + DAS1800_SELECT);
+ outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);
+ }
+
+ return 0;
+};
+
+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);
+ if(devpriv->iobase2)
+ release_region(devpriv->iobase2, DAS1800_SIZE);
+ if(dev->irq)
+ comedi_free_irq(dev->irq, dev);
+ 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);
+
+ printk("comedi%d: das1800: remove\n", dev->minor);
+
+ return 0;
+};
+
+static int das1800_recognize(char *name)
+{
+ if(!strcmp(name, "das-1701st"))
+ return das1701st;
+ if(!strcmp(name, "das-1701st-da"))
+ return das1701st_da;
+ if(!strcmp(name, "das-1702st"))
+ return das1702st;
+ if(!strcmp(name, "das-1702st-da"))
+ return das1702st_da;
+ if(!strcmp(name, "das-1702hr"))
+ return das1702hr;
+ if(!strcmp(name, "das-1702hr-da"))
+ return das1702hr_da;
+ if(!strcmp(name, "das-1701ao"))
+ return das1701ao;
+ if(!strcmp(name, "das-1702ao"))
+ return das1702ao;
+ if(!strcmp(name, "das-1801st"))
+ return das1801st;
+ if(!strcmp(name, "das-1801st-da"))
+ return das1801st_da;
+ if(!strcmp(name, "das-1802st"))
+ return das1802st;
+ if(!strcmp(name, "das-1802st-da"))
+ return das1802st_da;
+ if(!strcmp(name, "das-1802hr"))
+ return das1802hr;
+ if(!strcmp(name, "das-1802hr-da"))
+ return das1802hr_da;
+ 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;
+
+ 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) & 0x7; /* get id bits */
+ switch(id)
+ {
+ // das-1800st-da
+ case 0x3:
+ if(dev->board == das1801st_da || dev->board == das1802st_da ||
+ dev->board == das1701st_da || dev->board == das1702st_da)
+ {
+ printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
+ return dev->board;
+ }
+ printk(" Board model (probed, not recommended): DAS-1800ST-DA series\n");
+ return das1801st;
+ break;
+ // das-1800hr-da
+ case 0x4:
+ if(dev->board == das1802hr_da || dev->board == das1702hr_da)
+ {
+ printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
+ return dev->board;
+ }
+ printk(" Board model (probed, not recommended): DAS-1802HR-DA\n");
+ return das1802hr;
+ break;
+ case 0x5:
+ if(dev->board == das1801ao || dev->board == das1802ao ||
+ dev->board == das1701ao || dev->board == das1702ao)
+ {
+ printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
+ return dev->board;
+ }
+ printk(" Board model (probed, not recommended): DAS-1800AO series\n");
+ return das1801ao;
+ break;
+ case 0x6:
+ if(dev->board == das1802hr || dev->board == das1702hr)
+ {
+ printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
+ return dev->board;
+ }
+ printk(" Board model (probed, not recommended): DAS-1802HR\n");
+ return das1802hr;
+ break;
+ case 0x7:
+ if(dev->board == das1801st || dev->board == das1802st ||
+ dev->board == das1701st || dev->board == das1702st)
+ {
+ printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
+ return dev->board;
+ }
+ printk(" Board model (probed, not recommended): DAS-1800ST series\n");
+ return das1801st;
+ break;
+ case 0x8:
+ if(dev->board == das1801hc || dev->board == das1802hc)
+ {
+ printk(" Board model: %s\n", (das1800_boards + dev->board)->name);
+ return dev->board;
+ }
+ printk(" Board model (probed, not recommended): DAS-1800HC series\n");
+ return das1801hc;
+ break;
+ default :
+ printk(" Board model: probe returned 0x%x (unknown)\n", id);
+ return dev->board;
+ break;
+ }
+ return -1;
+}
+
+static int das1800_cancel(comedi_device *dev, comedi_subdevice *s)
+{
+ devpriv->forever = 0;
+ devpriv->count = 0;
+ disable_das1800(dev);
+ return 0;
+}
- /* analog input subdevice */
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_AI;
- 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_ai_range_lkup[dev->board];
- s->do_cmd = das1800_ai_do_cmd;
- s->do_cmdtest = das1800_ai_do_cmdtest;
- s->insn_read = das1800_ai_rinsn;
- s->cancel = das1800_cancel;
+static void das1800_interrupt(int irq, void *d, struct pt_regs *regs)
+{
+ int status, select;
+ comedi_device *dev = d;
+ comedi_subdevice *s = dev->subdevices + 0; /* analog input subdevice */
- /* analog out */
- s = dev->subdevices + 1;
- if(thisboard->ao_ability == 1)
+ status = inb(dev->iobase + DAS1800_STATUS);
+ /* if interrupt was not caused by das-1800 */
+ if(!(status & INT))
{
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE;
- s->n_chan = thisboard->ao_n_chan;
- s->maxdata = (1 << thisboard->resolution) - 1;
- s->range_table = &range_ao_1;
- s->insn_write = das1800_ao_winsn;
+ return;
+ }
+ // save contents of data select register so they can be restored later
+ select = inb(dev->iobase + DAS1800_SELECT) & 0xf;
+ // select adc for base address + 0
+ if(select != ADC) outb(ADC, dev->iobase + DAS1800_SELECT);
+ if(devpriv->dma0) /* if dma is enabled and generated the interrupt */
+ {
+ // dma buffer full or about-triggering (stop_src == TRIG_EXT)
+ if(status & (DMATC | CT0TC))
+ 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);
+ // restore data select register
+ if(select != ADC) outb(select, dev->iobase + DAS1800_SELECT);
+ /* if the card's fifo has overflowed */
+ if(status & OVF)
+ {
+ comedi_error(dev, "DAS1800 FIFO overflow");
+ das1800_cancel(dev, s);
+ comedi_error_done(dev, s);
+ return;
+ }
+ // if stop_src TRIG_EXT has occurred
+ if(status & CT0TC) devpriv->forever = 0;
+ /* stop taking data if appropriate */
+ if(devpriv->count == 0 && devpriv->forever == 0)
+ {
+ disable_das1800(dev); /* disable hardware conversions */
+ comedi_done(dev, s);
}
+
+ return;
+}
+
+static void das1800_handle_dma(comedi_device *dev, comedi_subdevice *s)
+{
+ unsigned long flags;
+ unsigned int numPoints, maxPoints, leftover, residue;
+ short dpnt;
+ short *buffer;
+ int unipolar;
+ int i;
+
+ flags = claim_dma_lock();
+ disable_dma(devpriv->dma_current);
+
+ // figure out how many points to read
+ maxPoints = devpriv->dma_buf_size / sizeof(short);
+ /* residue is the number of points left to be done on the dma
+ * transfer. It should always be zero at this point unless
+ * the stop_src is set to external triggering.
+ */
+ residue = get_dma_residue(devpriv->dma_current) / sizeof(short);
+ if(devpriv->forever)
+ numPoints = maxPoints - residue;
+ else
+ numPoints = devpriv->count;
+ if(numPoints > maxPoints - residue)
+ numPoints = maxPoints - residue;
+ // figure out how many points will be stored next time this buffer is used
+ leftover = 0;
+ if(devpriv->forever)
+ leftover = maxPoints;
else
{
- s->type = COMEDI_SUBD_UNUSED;
+ if(devpriv->dma1)
+ {
+ if(devpriv->count - 2 * maxPoints > 0)
+ leftover = devpriv->count - 2 * maxPoints;
+ }
+ else
+ {
+ if(devpriv->count - maxPoints > 0)
+ leftover = devpriv->count - maxPoints;
+ }
}
+ if(leftover > maxPoints)
+ leftover = maxPoints;
+ /* there should only be a residue if collection was stopped by having
+ * the stop_src set to an external trigger, in which case there
+ * will be no more data
+ */
+ if(residue)
+ leftover = 0;
- /* 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;
+ buffer = devpriv->dma_current_buf;
- /* 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;
+ /* see if card is using a unipolar or bipolar range */
+ unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
- disable_das1800(dev);
+ // read data from dma buffer
+ for( i = 0; i < numPoints; i++)
+ {
+ /* write data point to comedi buffer */
+ dpnt = buffer[i];
+ /* convert to unsigned type if we are in a bipolar mode */
+ if(!unipolar);
+ dpnt += 1 << (thisboard->resolution - 1);
+ write_to_buffer(dev, s, dpnt);
+ if(devpriv->count > 0) devpriv->count--;
+ }
- // initialize digital out channels
- outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL);
+ // re-enable channel
+ if(leftover)
+ {
+ set_dma_addr(devpriv->dma_current, (unsigned int) devpriv->dma_current_buf);
+ set_dma_count(devpriv->dma_current, leftover * sizeof(short));
+ enable_dma(devpriv->dma_current);
+ }
+ release_dma_lock(flags);
- // initialize analog out channels
- if(thisboard->ao_ability == 1)
+ // if we are using dual dma, read data from the other channel next time
+ if(devpriv->dma1)
{
- // select 'update' dac channel for baseAddress + 0x0
- outb(DAC(thisboard->ao_n_chan - 1), dev->iobase + DAS1800_SELECT);
- outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);
+ 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;
+ }
}
- return 0;
-};
+ /* clear interrupt */
+ outb(FNE, dev->iobase + DAS1800_STATUS);
-static int das1800_detach(comedi_device *dev)
+ return;
+}
+
+static void das1800_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s)
{
- printk("comedi%d: das1800: remove\n", dev->minor);
+ int i; /* loop index */
+ int numPoints = 0; /* number of points to read */
+ sampl_t dpnt;
+ int unipolar;
- /* only free stuff if it has been allocated by _attach */
- if(dev->iobase)
- release_region(dev->iobase, DAS1800_SIZE);
- if(devpriv->iobase2)
- release_region(devpriv->iobase2, DAS1800_SIZE);
- if(dev->irq)
- comedi_free_irq(dev->irq, dev);
- 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);
+ unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
- return 0;
-};
+ 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 */
+ dpnt = inw(dev->iobase + DAS1800_FIFO);
+ /* convert to unsigned type if we are in a bipolar mode */
+ if(!unipolar);
+ dpnt += 1 << (thisboard->resolution - 1);
+ write_to_buffer(dev, s, dpnt);
+ 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 int das1800_cancel(comedi_device *dev, comedi_subdevice *s)
+static void das1800_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s)
{
- devpriv->forever = 0;
- devpriv->count = 0;
- disable_das1800(dev);
- return 0;
+ sampl_t dpnt;
+ int unipolar;
+
+ unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+
+ while(inb(dev->iobase + DAS1800_STATUS) & FNE)
+ {
+ dpnt = inw(dev->iobase + DAS1800_FIFO);
+ /* convert to unsigned type if we are in a bipolar mode */
+ if(!unipolar);
+ dpnt += 1 << (thisboard->resolution - 1);
+ write_to_buffer(dev, s, dpnt);
+ if(devpriv->count > 0) devpriv->count--;
+ if(devpriv->count == 0 && devpriv->forever == 0)
+ break;
+ }
+ /* clear interrupt */
+ outb(FNE, dev->iobase + DAS1800_STATUS);
+
+ return;
+}
+
+/* utility function used by das1800 interrupt service routines */
+inline void write_to_buffer(comedi_device *dev, comedi_subdevice *s, sampl_t
+data_point) {
+ if(s->buf_int_ptr >= s->cur_trig.data_len )
+ {
+ s->buf_int_ptr = 0;
+ comedi_eobuf(dev, s);
+ }
+ *((sampl_t *)((void *)s->cur_trig.data + s->buf_int_ptr)) = data_point;
+ 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);
}
void disable_das1800(comedi_device *dev)
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++;
+ cmd->stop_src != TRIG_NONE &&
+ cmd->stop_src != TRIG_EXT) err++;
//compatibility check
if(cmd->scan_begin_src != TRIG_FOLLOW &&
cmd->convert_src != TRIG_TIMER) err++;
devpriv->irq_dma_bits |= FIMD; //interrupt fifo half full
break;
case TRIG_NONE:
+ case TRIG_EXT:
devpriv->forever = 1;
devpriv->count = 0;
devpriv->irq_dma_bits |= FIMD;
}
outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); // enable irq/dma
+
+ // set up dma
if(devpriv->dma0)
{
lock_flags = claim_dma_lock();
disable_dma(devpriv->dma0);
set_dma_addr(devpriv->dma0, (unsigned int) devpriv->dma0_buf);
+ // set appropriate size of transfer
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));
+ // set up dual dma if appropriate
+ if(devpriv->dma1 && (devpriv->count * sizeof(short) > devpriv->dma_buf_size || devpriv->forever))
+ {
+ disable_dma(devpriv->dma1);
+ set_dma_addr(devpriv->dma1, (unsigned int) devpriv->dma1_buf);
+ // set appropriate size of transfer
+ if(devpriv->count * sizeof(short) > 2 * devpriv->dma_buf_size || devpriv->forever)
+ set_dma_count(devpriv->dma1, devpriv->dma_buf_size);
+ else
+ set_dma_count(devpriv->dma1, devpriv->count * sizeof(short) - devpriv->dma_buf_size);
+ enable_dma(devpriv->dma1);
+ }
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 */