2 comedi/drivers/das1800.c
3 Driver for Keitley das1700/das1800 series boards
4 Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
6 COMEDI - Linux Control and Measurement Device Interface
7 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 Description: Keithley Metrabyte DAS1800 (& compatibles)
22 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
23 Devices: [Keithley Metrabyte] DAS-1701ST (das-1701st),
24 DAS-1701ST-DA (das-1701st-da), DAS-1701/AO (das-1701ao),
25 DAS-1702ST (das-1702st), DAS-1702ST-DA (das-1702st-da),
26 DAS-1702HR (das-1702hr), DAS-1702HR-DA (das-1702hr-da),
27 DAS-1702/AO (das-1702ao), DAS-1801ST (das-1801st),
28 DAS-1801ST-DA (das-1801st-da), DAS-1801HC (das-1801hc),
29 DAS-1801AO (das-1801ao), DAS-1802ST (das-1802st),
30 DAS-1802ST-DA (das-1802st-da), DAS-1802HR (das-1802hr),
31 DAS-1802HR-DA (das-1802hr-da), DAS-1802HC (das-1802hc),
32 DAS-1802AO (das-1802ao)
35 The waveform analog output on the 'ao' cards is not supported.
36 If you need it, send me (Frank Hess) an email.
38 Configuration options:
39 [0] - I/O port base address
40 [1] - IRQ (optional, required for timed or externally triggered conversions)
41 [2] - DMA0 (optional, requires irq)
42 [3] - DMA1 (optional, requires irq and dma0)
46 This driver supports the following Keithley boards:
69 [1] - irq (optional, required for timed or externally triggered conversions)
70 [2] - dma0 (optional, requires irq)
71 [3] - dma1 (optional, requires irq and dma0)
73 irq can be omitted, although the cmd interface will not work without it.
75 analog input cmd triggers supported:
76 start_src: TRIG_NOW | TRIG_EXT
77 scan_begin_src: TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT
78 scan_end_src: TRIG_COUNT
79 convert_src: TRIG_TIMER | TRIG_EXT (TRIG_EXT requires scan_begin_src == TRIG_FOLLOW)
80 stop_src: TRIG_COUNT | TRIG_EXT | TRIG_NONE
82 scan_begin_src triggers TRIG_TIMER and TRIG_EXT use the card's
83 'burst mode' which limits the valid conversion time to 64 microseconds
84 (convert_arg <= 64000). This limitation does not apply if scan_begin_src
88 Only the DAS-1801ST has been tested by me.
89 Unipolar and bipolar ranges cannot be mixed in the channel/gain list.
92 Make it automatically allocate irq and dma channels if they are not specified
93 Add support for analog out on 'ao' cards
94 read insn for analog out
97 #include <linux/module.h>
98 #include <linux/interrupt.h>
99 #include <linux/slab.h>
100 #include <linux/io.h>
101 #include "../comedidev.h"
106 #include "comedi_fc.h"
109 #define DAS1800_SIZE 16 /* uses 16 io addresses */
110 #define FIFO_SIZE 1024 /* 1024 sample fifo */
111 #define TIMER_BASE 200 /* 5 Mhz master clock */
112 #define UNIPOLAR 0x4 /* bit that determines whether input range is uni/bipolar */
113 #define DMA_BUF_SIZE 0x1ff00 /* size in bytes of dma buffers */
115 /* Registers for the das1800 */
116 #define DAS1800_FIFO 0x0
117 #define DAS1800_QRAM 0x0
118 #define DAS1800_DAC 0x0
119 #define DAS1800_SELECT 0x2
122 #define DAC(a) (0x2 + a)
123 #define DAS1800_DIGITAL 0x3
124 #define DAS1800_CONTROL_A 0x4
131 #define DAS1800_CONTROL_B 0x5
135 #define DMA_CH5_CH6 0x5
136 #define DMA_CH6_CH7 0x6
137 #define DMA_CH7_CH5 0x7
138 #define DMA_ENABLED 0x3 /* mask used to determine if dma is enabled */
147 #define DAS1800_CONTROL_C 0X6
155 #define DAS1800_STATUS 0x7
156 /* bits that prevent interrupt status bits (and CVEN) from being cleared on write */
157 #define CLEAR_INTR_MASK (CVEN_MASK | 0x1f)
164 #define CVEN_MASK 0x40 /* masks CVEN on write */
166 #define DAS1800_BURST_LENGTH 0x8
167 #define DAS1800_BURST_RATE 0x9
168 #define DAS1800_QRAM_ADDRESS 0xa
169 #define DAS1800_COUNTER 0xc
171 #define IOBASE2 0x400 /* offset of additional ioports used on 'ao' cards */
174 das1701st, das1701st_da, das1702st, das1702st_da, das1702hr,
176 das1701ao, das1702ao, das1801st, das1801st_da, das1802st, das1802st_da,
177 das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao
180 /* analog input ranges */
181 static const struct comedi_lrange range_ai_das1801 = {
195 static const struct comedi_lrange range_ai_das1802 = {
209 struct das1800_board {
211 int ai_speed; /* max conversion period in nanoseconds */
212 int resolution; /* bits of ai resolution */
213 int qram_len; /* length of card's channel / gain queue */
214 int common; /* supports AREF_COMMON flag */
215 int do_n_chan; /* number of digital output channels */
216 int ao_ability; /* 0 == no analog out, 1 == basic analog out, 2 == waveform analog out */
217 int ao_n_chan; /* number of analog out channels */
218 const struct comedi_lrange *range_ai; /* available input ranges */
221 /* Warning: the maximum conversion speeds listed below are
222 * not always achievable depending on board setup (see
225 static const struct das1800_board das1800_boards[] = {
227 .name = "das-1701st",
235 .range_ai = &range_ai_das1801,
238 .name = "das-1701st-da",
246 .range_ai = &range_ai_das1801,
249 .name = "das-1702st",
257 .range_ai = &range_ai_das1802,
260 .name = "das-1702st-da",
268 .range_ai = &range_ai_das1802,
271 .name = "das-1702hr",
279 .range_ai = &range_ai_das1802,
282 .name = "das-1702hr-da",
290 .range_ai = &range_ai_das1802,
293 .name = "das-1701ao",
301 .range_ai = &range_ai_das1801,
304 .name = "das-1702ao",
312 .range_ai = &range_ai_das1802,
315 .name = "das-1801st",
323 .range_ai = &range_ai_das1801,
326 .name = "das-1801st-da",
334 .range_ai = &range_ai_das1801,
337 .name = "das-1802st",
345 .range_ai = &range_ai_das1802,
348 .name = "das-1802st-da",
356 .range_ai = &range_ai_das1802,
359 .name = "das-1802hr",
367 .range_ai = &range_ai_das1802,
370 .name = "das-1802hr-da",
378 .range_ai = &range_ai_das1802,
381 .name = "das-1801hc",
389 .range_ai = &range_ai_das1801,
392 .name = "das-1802hc",
400 .range_ai = &range_ai_das1802,
403 .name = "das-1801ao",
411 .range_ai = &range_ai_das1801,
414 .name = "das-1802ao",
422 .range_ai = &range_ai_das1802,
426 struct das1800_private {
427 volatile unsigned int count; /* number of data points left to be taken */
428 unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */
429 unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */
430 int irq_dma_bits; /* bits for control register b */
431 /* dma bits for control register b, stored so that dma can be
432 * turned on and off */
434 unsigned int dma0; /* dma channels used */
436 volatile unsigned int dma_current; /* dma channel currently in use */
437 uint16_t *ai_buf0; /* pointers to dma buffers */
439 uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */
440 unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */
441 unsigned long iobase2; /* secondary io address used for analog out on 'ao' boards */
442 short ao_update_bits; /* remembers the last write to the 'update' dac */
445 /* analog out range for 'ao' boards */
447 static const struct comedi_lrange range_ao_2 = {
456 static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev,
459 const struct das1800_board *thisboard = comedi_board(dev);
461 sample += 1 << (thisboard->resolution - 1);
465 static void munge_data(struct comedi_device *dev, uint16_t * array,
466 unsigned int num_elements)
471 /* see if card is using a unipolar or bipolar range so we can munge data correctly */
472 unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
474 /* convert to unsigned type if we are in a bipolar mode */
476 for (i = 0; i < num_elements; i++)
477 array[i] = munge_bipolar_sample(dev, array[i]);
481 static void das1800_handle_fifo_half_full(struct comedi_device *dev,
482 struct comedi_subdevice *s)
484 struct das1800_private *devpriv = dev->private;
485 int numPoints = 0; /* number of points to read */
486 struct comedi_cmd *cmd = &s->async->cmd;
488 numPoints = FIFO_SIZE / 2;
489 /* if we only need some of the points */
490 if (cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints)
491 numPoints = devpriv->count;
492 insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints);
493 munge_data(dev, devpriv->ai_buf0, numPoints);
494 cfc_write_array_to_buffer(s, devpriv->ai_buf0,
495 numPoints * sizeof(devpriv->ai_buf0[0]));
496 if (cmd->stop_src == TRIG_COUNT)
497 devpriv->count -= numPoints;
501 static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
502 struct comedi_subdevice *s)
504 struct das1800_private *devpriv = dev->private;
507 struct comedi_cmd *cmd = &s->async->cmd;
509 unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
511 while (inb(dev->iobase + DAS1800_STATUS) & FNE) {
512 if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0)
514 dpnt = inw(dev->iobase + DAS1800_FIFO);
515 /* convert to unsigned type if we are in a bipolar mode */
518 dpnt = munge_bipolar_sample(dev, dpnt);
519 cfc_write_to_buffer(s, dpnt);
520 if (cmd->stop_src == TRIG_COUNT)
527 /* Utility function used by das1800_flush_dma() and das1800_handle_dma().
528 * Assumes dma lock is held */
529 static void das1800_flush_dma_channel(struct comedi_device *dev,
530 struct comedi_subdevice *s,
531 unsigned int channel, uint16_t *buffer)
533 struct das1800_private *devpriv = dev->private;
534 unsigned int num_bytes, num_samples;
535 struct comedi_cmd *cmd = &s->async->cmd;
537 disable_dma(channel);
539 /* clear flip-flop to make sure 2-byte registers
540 * get set correctly */
541 clear_dma_ff(channel);
543 /* figure out how many points to read */
544 num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel);
545 num_samples = num_bytes / sizeof(short);
547 /* if we only need some of the points */
548 if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples)
549 num_samples = devpriv->count;
551 munge_data(dev, buffer, num_samples);
552 cfc_write_array_to_buffer(s, buffer, num_bytes);
553 if (s->async->cmd.stop_src == TRIG_COUNT)
554 devpriv->count -= num_samples;
559 /* flushes remaining data from board when external trigger has stopped acquisition
560 * and we are using dma transfers */
561 static void das1800_flush_dma(struct comedi_device *dev,
562 struct comedi_subdevice *s)
564 struct das1800_private *devpriv = dev->private;
566 const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
568 flags = claim_dma_lock();
569 das1800_flush_dma_channel(dev, s, devpriv->dma_current,
570 devpriv->dma_current_buf);
573 /* switch to other channel and flush it */
574 if (devpriv->dma_current == devpriv->dma0) {
575 devpriv->dma_current = devpriv->dma1;
576 devpriv->dma_current_buf = devpriv->ai_buf1;
578 devpriv->dma_current = devpriv->dma0;
579 devpriv->dma_current_buf = devpriv->ai_buf0;
581 das1800_flush_dma_channel(dev, s, devpriv->dma_current,
582 devpriv->dma_current_buf);
585 release_dma_lock(flags);
587 /* get any remaining samples in fifo */
588 das1800_handle_fifo_not_empty(dev, s);
593 static void das1800_handle_dma(struct comedi_device *dev,
594 struct comedi_subdevice *s, unsigned int status)
596 struct das1800_private *devpriv = dev->private;
598 const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
600 flags = claim_dma_lock();
601 das1800_flush_dma_channel(dev, s, devpriv->dma_current,
602 devpriv->dma_current_buf);
603 /* re-enable dma channel */
604 set_dma_addr(devpriv->dma_current,
605 virt_to_bus(devpriv->dma_current_buf));
606 set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size);
607 enable_dma(devpriv->dma_current);
608 release_dma_lock(flags);
610 if (status & DMATC) {
611 /* clear DMATC interrupt bit */
612 outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS);
613 /* switch dma channels for next time, if appropriate */
615 /* read data from the other channel next time */
616 if (devpriv->dma_current == devpriv->dma0) {
617 devpriv->dma_current = devpriv->dma1;
618 devpriv->dma_current_buf = devpriv->ai_buf1;
620 devpriv->dma_current = devpriv->dma0;
621 devpriv->dma_current_buf = devpriv->ai_buf0;
629 static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
631 struct das1800_private *devpriv = dev->private;
633 outb(0x0, dev->iobase + DAS1800_STATUS); /* disable conversions */
634 outb(0x0, dev->iobase + DAS1800_CONTROL_B); /* disable interrupts and dma */
635 outb(0x0, dev->iobase + DAS1800_CONTROL_A); /* disable and clear fifo and stop triggering */
637 disable_dma(devpriv->dma0);
639 disable_dma(devpriv->dma1);
643 /* the guts of the interrupt handler, that is shared with das1800_ai_poll */
644 static void das1800_ai_handler(struct comedi_device *dev)
646 struct das1800_private *devpriv = dev->private;
647 struct comedi_subdevice *s = &dev->subdevices[0];
648 struct comedi_async *async = s->async;
649 struct comedi_cmd *cmd = &async->cmd;
650 unsigned int status = inb(dev->iobase + DAS1800_STATUS);
653 /* select adc for base address + 0 */
654 outb(ADC, dev->iobase + DAS1800_SELECT);
655 /* dma buffer full */
656 if (devpriv->irq_dma_bits & DMA_ENABLED) {
657 /* look for data from dma transfer even if dma terminal count hasn't happened yet */
658 das1800_handle_dma(dev, s, status);
659 } else if (status & FHF) { /* if fifo half full */
660 das1800_handle_fifo_half_full(dev, s);
661 } else if (status & FNE) { /* if fifo not empty */
662 das1800_handle_fifo_not_empty(dev, s);
665 async->events |= COMEDI_CB_BLOCK;
666 /* if the card's fifo has overflowed */
668 /* clear OVF interrupt bit */
669 outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS);
670 comedi_error(dev, "DAS1800 FIFO overflow");
671 das1800_cancel(dev, s);
672 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
673 comedi_event(dev, s);
676 /* stop taking data if appropriate */
677 /* stop_src TRIG_EXT */
678 if (status & CT0TC) {
679 /* clear CT0TC interrupt bit */
680 outb(CLEAR_INTR_MASK & ~CT0TC, dev->iobase + DAS1800_STATUS);
681 /* make sure we get all remaining data from board before quitting */
682 if (devpriv->irq_dma_bits & DMA_ENABLED)
683 das1800_flush_dma(dev, s);
685 das1800_handle_fifo_not_empty(dev, s);
686 das1800_cancel(dev, s); /* disable hardware conversions */
687 async->events |= COMEDI_CB_EOA;
688 } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */
689 das1800_cancel(dev, s); /* disable hardware conversions */
690 async->events |= COMEDI_CB_EOA;
693 comedi_event(dev, s);
698 static int das1800_ai_poll(struct comedi_device *dev,
699 struct comedi_subdevice *s)
703 /* prevent race with interrupt handler */
704 spin_lock_irqsave(&dev->spinlock, flags);
705 das1800_ai_handler(dev);
706 spin_unlock_irqrestore(&dev->spinlock, flags);
708 return s->async->buf_write_count - s->async->buf_read_count;
711 static irqreturn_t das1800_interrupt(int irq, void *d)
713 struct comedi_device *dev = d;
716 if (!dev->attached) {
717 comedi_error(dev, "premature interrupt");
721 /* Prevent race with das1800_ai_poll() on multi processor systems.
722 * Also protects indirect addressing in das1800_ai_handler */
723 spin_lock(&dev->spinlock);
724 status = inb(dev->iobase + DAS1800_STATUS);
726 /* if interrupt was not caused by das-1800 */
727 if (!(status & INT)) {
728 spin_unlock(&dev->spinlock);
731 /* clear the interrupt status bit INT */
732 outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS);
733 /* handle interrupt */
734 das1800_ai_handler(dev);
736 spin_unlock(&dev->spinlock);
740 /* converts requested conversion timing to timing compatible with
741 * hardware, used only when card is in 'burst mode'
743 static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode)
745 unsigned int micro_sec;
747 /* in burst mode, the maximum conversion time is 64 microseconds */
748 if (convert_arg > 64000)
751 /* the conversion time must be an integral number of microseconds */
752 switch (round_mode) {
753 case TRIG_ROUND_NEAREST:
755 micro_sec = (convert_arg + 500) / 1000;
757 case TRIG_ROUND_DOWN:
758 micro_sec = convert_arg / 1000;
761 micro_sec = (convert_arg - 1) / 1000 + 1;
765 /* return number of nanoseconds */
766 return micro_sec * 1000;
769 /* test analog input cmd */
770 static int das1800_ai_do_cmdtest(struct comedi_device *dev,
771 struct comedi_subdevice *s,
772 struct comedi_cmd *cmd)
774 const struct das1800_board *thisboard = comedi_board(dev);
775 struct das1800_private *devpriv = dev->private;
777 unsigned int tmp_arg;
781 /* Step 1 : check if triggers are trivially valid */
783 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
784 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
785 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
786 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
787 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
788 err |= cfc_check_trigger_src(&cmd->stop_src,
789 TRIG_COUNT | TRIG_EXT | TRIG_NONE);
794 /* Step 2a : make sure trigger sources are unique */
796 err |= cfc_check_trigger_is_unique(cmd->start_src);
797 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
798 err |= cfc_check_trigger_is_unique(cmd->convert_src);
799 err |= cfc_check_trigger_is_unique(cmd->stop_src);
801 /* Step 2b : and mutually compatible */
803 if (cmd->scan_begin_src != TRIG_FOLLOW &&
804 cmd->convert_src != TRIG_TIMER)
810 /* Step 3: check if arguments are trivially valid */
812 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
814 if (cmd->convert_src == TRIG_TIMER)
815 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
816 thisboard->ai_speed);
818 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
819 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
821 switch (cmd->stop_src) {
823 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
826 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
835 /* step 4: fix up any arguments */
837 if (cmd->convert_src == TRIG_TIMER) {
838 /* if we are not in burst mode */
839 if (cmd->scan_begin_src == TRIG_FOLLOW) {
840 tmp_arg = cmd->convert_arg;
841 /* calculate counter values that give desired timing */
842 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
843 &(devpriv->divisor1),
844 &(devpriv->divisor2),
847 flags & TRIG_ROUND_MASK);
848 if (tmp_arg != cmd->convert_arg)
851 /* if we are in burst mode */
853 /* check that convert_arg is compatible */
854 tmp_arg = cmd->convert_arg;
856 burst_convert_arg(cmd->convert_arg,
857 cmd->flags & TRIG_ROUND_MASK);
858 if (tmp_arg != cmd->convert_arg)
861 if (cmd->scan_begin_src == TRIG_TIMER) {
862 /* if scans are timed faster than conversion rate allows */
863 if (cmd->convert_arg * cmd->chanlist_len >
864 cmd->scan_begin_arg) {
865 cmd->scan_begin_arg =
870 tmp_arg = cmd->scan_begin_arg;
871 /* calculate counter values that give desired timing */
872 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
882 if (tmp_arg != cmd->scan_begin_arg)
891 /* make sure user is not trying to mix unipolar and bipolar ranges */
893 unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR;
894 for (i = 1; i < cmd->chanlist_len; i++) {
895 if (unipolar != (CR_RANGE(cmd->chanlist[i]) & UNIPOLAR)) {
897 "unipolar and bipolar ranges cannot be mixed in the chanlist");
910 /* returns appropriate bits for control register a, depending on command */
911 static int control_a_bits(const struct comedi_cmd *cmd)
915 control_a = FFEN; /* enable fifo */
916 if (cmd->stop_src == TRIG_EXT)
918 switch (cmd->start_src) {
920 control_a |= TGEN | CGSL;
932 /* returns appropriate bits for control register c, depending on command */
933 static int control_c_bits(const struct comedi_cmd *cmd)
938 /* set clock source to internal or external, select analog reference,
939 * select unipolar / bipolar
941 aref = CR_AREF(cmd->chanlist[0]);
942 control_c = UQEN; /* enable upper qram addresses */
943 if (aref != AREF_DIFF)
945 if (aref == AREF_COMMON)
947 /* if a unipolar range was selected */
948 if (CR_RANGE(cmd->chanlist[0]) & UNIPOLAR)
950 switch (cmd->scan_begin_src) {
951 case TRIG_FOLLOW: /* not in burst mode */
952 switch (cmd->convert_src) {
954 /* trig on cascaded counters */
958 /* trig on falling edge of external trigger */
966 /* burst mode with internal pacer clock */
967 control_c |= BMDE | IPCLK;
970 /* burst mode with external trigger */
971 control_c |= BMDE | XPCLK;
980 /* loads counters with divisor1, divisor2 from private structure */
981 static int das1800_set_frequency(struct comedi_device *dev)
983 struct das1800_private *devpriv = dev->private;
986 /* counter 1, mode 2 */
987 if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1,
990 /* counter 2, mode 2 */
991 if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2,
1000 /* sets up counters */
1001 static int setup_counters(struct comedi_device *dev,
1002 const struct comedi_cmd *cmd)
1004 struct das1800_private *devpriv = dev->private;
1005 unsigned int period;
1007 /* setup cascaded counters for conversion/scan frequency */
1008 switch (cmd->scan_begin_src) {
1009 case TRIG_FOLLOW: /* not in burst mode */
1010 if (cmd->convert_src == TRIG_TIMER) {
1011 /* set conversion frequency */
1012 period = cmd->convert_arg;
1013 i8253_cascade_ns_to_timer_2div(TIMER_BASE,
1019 if (das1800_set_frequency(dev) < 0)
1023 case TRIG_TIMER: /* in burst mode */
1024 /* set scan frequency */
1025 period = cmd->scan_begin_arg;
1026 i8253_cascade_ns_to_timer_2div(TIMER_BASE, &devpriv->divisor1,
1027 &devpriv->divisor2, &period,
1028 cmd->flags & TRIG_ROUND_MASK);
1029 if (das1800_set_frequency(dev) < 0)
1036 /* setup counter 0 for 'about triggering' */
1037 if (cmd->stop_src == TRIG_EXT) {
1038 /* load counter 0 in mode 0 */
1039 i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0);
1045 /* utility function that suggests a dma transfer size based on the conversion period 'ns' */
1046 static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd)
1048 unsigned int size = DMA_BUF_SIZE;
1049 static const int sample_size = 2; /* size in bytes of one sample from board */
1050 unsigned int fill_time = 300000000; /* target time in nanoseconds for filling dma buffer */
1051 unsigned int max_size; /* maximum size we will allow for a transfer */
1053 /* make dma buffer fill in 0.3 seconds for timed modes */
1054 switch (cmd->scan_begin_src) {
1055 case TRIG_FOLLOW: /* not in burst mode */
1056 if (cmd->convert_src == TRIG_TIMER)
1057 size = (fill_time / cmd->convert_arg) * sample_size;
1060 size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) *
1064 size = DMA_BUF_SIZE;
1068 /* set a minimum and maximum size allowed */
1069 max_size = DMA_BUF_SIZE;
1070 /* if we are taking limited number of conversions, limit transfer size to that */
1071 if (cmd->stop_src == TRIG_COUNT &&
1072 cmd->stop_arg * cmd->chanlist_len * sample_size < max_size)
1073 max_size = cmd->stop_arg * cmd->chanlist_len * sample_size;
1075 if (size > max_size)
1077 if (size < sample_size)
1084 static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
1086 struct das1800_private *devpriv = dev->private;
1087 unsigned long lock_flags;
1088 const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
1090 if ((devpriv->irq_dma_bits & DMA_ENABLED) == 0)
1093 /* determine a reasonable dma transfer size */
1094 devpriv->dma_transfer_size = suggest_transfer_size(cmd);
1095 lock_flags = claim_dma_lock();
1096 disable_dma(devpriv->dma0);
1097 /* clear flip-flop to make sure 2-byte registers for
1098 * count and address get set correctly */
1099 clear_dma_ff(devpriv->dma0);
1100 set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0));
1101 /* set appropriate size of transfer */
1102 set_dma_count(devpriv->dma0, devpriv->dma_transfer_size);
1103 devpriv->dma_current = devpriv->dma0;
1104 devpriv->dma_current_buf = devpriv->ai_buf0;
1105 enable_dma(devpriv->dma0);
1106 /* set up dual dma if appropriate */
1108 disable_dma(devpriv->dma1);
1109 /* clear flip-flop to make sure 2-byte registers for
1110 * count and address get set correctly */
1111 clear_dma_ff(devpriv->dma1);
1112 set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1));
1113 /* set appropriate size of transfer */
1114 set_dma_count(devpriv->dma1, devpriv->dma_transfer_size);
1115 enable_dma(devpriv->dma1);
1117 release_dma_lock(lock_flags);
1122 /* programs channel/gain list into card */
1123 static void program_chanlist(struct comedi_device *dev,
1124 const struct comedi_cmd *cmd)
1126 int i, n, chan_range;
1127 unsigned long irq_flags;
1128 const int range_mask = 0x3; /* masks unipolar/bipolar bit off range */
1129 const int range_bitshift = 8;
1131 n = cmd->chanlist_len;
1132 /* spinlock protects indirect addressing */
1133 spin_lock_irqsave(&dev->spinlock, irq_flags);
1134 outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */
1135 outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*set QRAM address start */
1136 /* make channel / gain list */
1137 for (i = 0; i < n; i++) {
1139 CR_CHAN(cmd->chanlist[i]) |
1140 ((CR_RANGE(cmd->chanlist[i]) & range_mask) <<
1142 outw(chan_range, dev->iobase + DAS1800_QRAM);
1144 outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*finish write to QRAM */
1145 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
1150 /* analog input do_cmd */
1151 static int das1800_ai_do_cmd(struct comedi_device *dev,
1152 struct comedi_subdevice *s)
1154 struct das1800_private *devpriv = dev->private;
1156 int control_a, control_c;
1157 struct comedi_async *async = s->async;
1158 const struct comedi_cmd *cmd = &async->cmd;
1162 "no irq assigned for das-1800, cannot do hardware conversions");
1166 /* disable dma on TRIG_WAKE_EOS, or TRIG_RT
1167 * (because dma in handler is unsafe at hard real-time priority) */
1168 if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT))
1169 devpriv->irq_dma_bits &= ~DMA_ENABLED;
1171 devpriv->irq_dma_bits |= devpriv->dma_bits;
1172 /* interrupt on end of conversion for TRIG_WAKE_EOS */
1173 if (cmd->flags & TRIG_WAKE_EOS) {
1174 /* interrupt fifo not empty */
1175 devpriv->irq_dma_bits &= ~FIMD;
1177 /* interrupt fifo half full */
1178 devpriv->irq_dma_bits |= FIMD;
1180 /* determine how many conversions we need */
1181 if (cmd->stop_src == TRIG_COUNT)
1182 devpriv->count = cmd->stop_arg * cmd->chanlist_len;
1184 das1800_cancel(dev, s);
1186 /* determine proper bits for control registers */
1187 control_a = control_a_bits(cmd);
1188 control_c = control_c_bits(cmd);
1190 /* setup card and start */
1191 program_chanlist(dev, cmd);
1192 ret = setup_counters(dev, cmd);
1194 comedi_error(dev, "Error setting up counters");
1197 setup_dma(dev, cmd);
1198 outb(control_c, dev->iobase + DAS1800_CONTROL_C);
1199 /* set conversion rate and length for burst mode */
1200 if (control_c & BMDE) {
1201 /* program conversion period with number of microseconds minus 1 */
1202 outb(cmd->convert_arg / 1000 - 1,
1203 dev->iobase + DAS1800_BURST_RATE);
1204 outb(cmd->chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH);
1206 outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); /* enable irq/dma */
1207 outb(control_a, dev->iobase + DAS1800_CONTROL_A); /* enable fifo and triggering */
1208 outb(CVEN, dev->iobase + DAS1800_STATUS); /* enable conversions */
1213 /* read analog input */
1214 static int das1800_ai_rinsn(struct comedi_device *dev,
1215 struct comedi_subdevice *s,
1216 struct comedi_insn *insn, unsigned int *data)
1218 const struct das1800_board *thisboard = comedi_board(dev);
1220 int chan, range, aref, chan_range;
1224 unsigned long irq_flags;
1226 /* set up analog reference and unipolar / bipolar mode */
1227 aref = CR_AREF(insn->chanspec);
1229 if (aref != AREF_DIFF)
1231 if (aref == AREF_COMMON)
1233 /* if a unipolar range was selected */
1234 if (CR_RANGE(insn->chanspec) & UNIPOLAR)
1237 outb(conv_flags, dev->iobase + DAS1800_CONTROL_C); /* software conversion enabled */
1238 outb(CVEN, dev->iobase + DAS1800_STATUS); /* enable conversions */
1239 outb(0x0, dev->iobase + DAS1800_CONTROL_A); /* reset fifo */
1240 outb(FFEN, dev->iobase + DAS1800_CONTROL_A);
1242 chan = CR_CHAN(insn->chanspec);
1243 /* mask of unipolar/bipolar bit from range */
1244 range = CR_RANGE(insn->chanspec) & 0x3;
1245 chan_range = chan | (range << 8);
1246 spin_lock_irqsave(&dev->spinlock, irq_flags);
1247 outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */
1248 outb(0x0, dev->iobase + DAS1800_QRAM_ADDRESS); /* set QRAM address start */
1249 outw(chan_range, dev->iobase + DAS1800_QRAM);
1250 outb(0x0, dev->iobase + DAS1800_QRAM_ADDRESS); /*finish write to QRAM */
1251 outb(ADC, dev->iobase + DAS1800_SELECT); /* select ADC for baseAddress + 0x0 */
1253 for (n = 0; n < insn->n; n++) {
1254 /* trigger conversion */
1255 outb(0, dev->iobase + DAS1800_FIFO);
1256 for (i = 0; i < timeout; i++) {
1257 if (inb(dev->iobase + DAS1800_STATUS) & FNE)
1261 comedi_error(dev, "timeout");
1265 dpnt = inw(dev->iobase + DAS1800_FIFO);
1266 /* shift data to offset binary for bipolar ranges */
1267 if ((conv_flags & UB) == 0)
1268 dpnt += 1 << (thisboard->resolution - 1);
1272 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
1277 /* writes to an analog output channel */
1278 static int das1800_ao_winsn(struct comedi_device *dev,
1279 struct comedi_subdevice *s,
1280 struct comedi_insn *insn, unsigned int *data)
1282 const struct das1800_board *thisboard = comedi_board(dev);
1283 struct das1800_private *devpriv = dev->private;
1284 int chan = CR_CHAN(insn->chanspec);
1285 /* int range = CR_RANGE(insn->chanspec); */
1286 int update_chan = thisboard->ao_n_chan - 1;
1288 unsigned long irq_flags;
1290 /* card expects two's complement data */
1291 output = data[0] - (1 << (thisboard->resolution - 1));
1292 /* if the write is to the 'update' channel, we need to remember its value */
1293 if (chan == update_chan)
1294 devpriv->ao_update_bits = output;
1295 /* write to channel */
1296 spin_lock_irqsave(&dev->spinlock, irq_flags);
1297 outb(DAC(chan), dev->iobase + DAS1800_SELECT); /* select dac channel for baseAddress + 0x0 */
1298 outw(output, dev->iobase + DAS1800_DAC);
1299 /* now we need to write to 'update' channel to update all dac channels */
1300 if (chan != update_chan) {
1301 outb(DAC(update_chan), dev->iobase + DAS1800_SELECT); /* select 'update' channel for baseAddress + 0x0 */
1302 outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);
1304 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
1309 /* reads from digital input channels */
1310 static int das1800_di_rbits(struct comedi_device *dev,
1311 struct comedi_subdevice *s,
1312 struct comedi_insn *insn, unsigned int *data)
1315 data[1] = inb(dev->iobase + DAS1800_DIGITAL) & 0xf;
1321 static int das1800_do_wbits(struct comedi_device *dev,
1322 struct comedi_subdevice *s,
1323 struct comedi_insn *insn,
1326 if (comedi_dio_update_state(s, data))
1327 outb(s->state, dev->iobase + DAS1800_DIGITAL);
1334 static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
1337 struct das1800_private *devpriv = dev->private;
1338 unsigned long flags;
1340 /* need an irq to do dma */
1341 if (dev->irq && dma0) {
1342 /* encode dma0 and dma1 into 2 digit hexadecimal for switch */
1343 switch ((dma0 & 0x7) | (dma1 << 4)) {
1344 case 0x5: /* dma0 == 5 */
1345 devpriv->dma_bits |= DMA_CH5;
1347 case 0x6: /* dma0 == 6 */
1348 devpriv->dma_bits |= DMA_CH6;
1350 case 0x7: /* dma0 == 7 */
1351 devpriv->dma_bits |= DMA_CH7;
1353 case 0x65: /* dma0 == 5, dma1 == 6 */
1354 devpriv->dma_bits |= DMA_CH5_CH6;
1356 case 0x76: /* dma0 == 6, dma1 == 7 */
1357 devpriv->dma_bits |= DMA_CH6_CH7;
1359 case 0x57: /* dma0 == 7, dma1 == 5 */
1360 devpriv->dma_bits |= DMA_CH7_CH5;
1363 dev_err(dev->class_dev,
1364 "only supports dma channels 5 through 7\n");
1365 dev_err(dev->class_dev,
1366 "Dual dma only allows the following combinations:\n");
1367 dev_err(dev->class_dev,
1368 "dma 5,6 / 6,7 / or 7,5\n");
1372 if (request_dma(dma0, dev->driver->driver_name)) {
1373 dev_err(dev->class_dev,
1374 "failed to allocate dma channel %i\n", dma0);
1377 devpriv->dma0 = dma0;
1378 devpriv->dma_current = dma0;
1380 if (request_dma(dma1, dev->driver->driver_name)) {
1381 dev_err(dev->class_dev,
1382 "failed to allocate dma channel %i\n",
1386 devpriv->dma1 = dma1;
1388 devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
1389 if (devpriv->ai_buf0 == NULL)
1391 devpriv->dma_current_buf = devpriv->ai_buf0;
1394 kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
1395 if (devpriv->ai_buf1 == NULL)
1398 flags = claim_dma_lock();
1399 disable_dma(devpriv->dma0);
1400 set_dma_mode(devpriv->dma0, DMA_MODE_READ);
1402 disable_dma(devpriv->dma1);
1403 set_dma_mode(devpriv->dma1, DMA_MODE_READ);
1405 release_dma_lock(flags);
1410 static int das1800_probe(struct comedi_device *dev)
1415 id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf; /* get id bits */
1416 board = ((struct das1800_board *)dev->board_ptr) - das1800_boards;
1420 if (board == das1801st_da || board == das1802st_da ||
1421 board == das1701st_da || board == das1702st_da) {
1422 dev_dbg(dev->class_dev, "Board model: %s\n",
1423 das1800_boards[board].name);
1427 (" Board model (probed, not recommended): das-1800st-da series\n");
1431 if (board == das1802hr_da || board == das1702hr_da) {
1432 dev_dbg(dev->class_dev, "Board model: %s\n",
1433 das1800_boards[board].name);
1437 (" Board model (probed, not recommended): das-1802hr-da\n");
1441 if (board == das1801ao || board == das1802ao ||
1442 board == das1701ao || board == das1702ao) {
1443 dev_dbg(dev->class_dev, "Board model: %s\n",
1444 das1800_boards[board].name);
1448 (" Board model (probed, not recommended): das-1800ao series\n");
1452 if (board == das1802hr || board == das1702hr) {
1453 dev_dbg(dev->class_dev, "Board model: %s\n",
1454 das1800_boards[board].name);
1458 (" Board model (probed, not recommended): das-1802hr\n");
1462 if (board == das1801st || board == das1802st ||
1463 board == das1701st || board == das1702st) {
1464 dev_dbg(dev->class_dev, "Board model: %s\n",
1465 das1800_boards[board].name);
1469 (" Board model (probed, not recommended): das-1800st series\n");
1473 if (board == das1801hc || board == das1802hc) {
1474 dev_dbg(dev->class_dev, "Board model: %s\n",
1475 das1800_boards[board].name);
1479 (" Board model (probed, not recommended): das-1800hc series\n");
1484 (" Board model: probe returned 0x%x (unknown, please report)\n",
1492 static int das1800_attach(struct comedi_device *dev,
1493 struct comedi_devconfig *it)
1495 const struct das1800_board *thisboard = comedi_board(dev);
1496 struct das1800_private *devpriv;
1497 struct comedi_subdevice *s;
1498 unsigned int irq = it->options[1];
1499 unsigned int dma0 = it->options[2];
1500 unsigned int dma1 = it->options[3];
1504 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1508 ret = comedi_request_region(dev, it->options[0], DAS1800_SIZE);
1512 board = das1800_probe(dev);
1514 dev_err(dev->class_dev, "unable to determine board type\n");
1518 dev->board_ptr = das1800_boards + board;
1519 thisboard = comedi_board(dev);
1520 dev->board_name = thisboard->name;
1522 /* if it is an 'ao' board with fancy analog out then we need extra io ports */
1523 if (thisboard->ao_ability == 2) {
1524 unsigned long iobase2 = dev->iobase + IOBASE2;
1526 ret = __comedi_request_region(dev, iobase2, DAS1800_SIZE);
1529 devpriv->iobase2 = iobase2;
1534 if (request_irq(irq, das1800_interrupt, 0,
1535 dev->driver->driver_name, dev)) {
1536 dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
1543 /* set bits that tell card which irq to use */
1548 devpriv->irq_dma_bits |= 0x8;
1551 devpriv->irq_dma_bits |= 0x10;
1554 devpriv->irq_dma_bits |= 0x18;
1557 devpriv->irq_dma_bits |= 0x28;
1560 devpriv->irq_dma_bits |= 0x30;
1563 devpriv->irq_dma_bits |= 0x38;
1566 dev_err(dev->class_dev, "irq out of range\n");
1571 ret = das1800_init_dma(dev, dma0, dma1);
1575 if (devpriv->ai_buf0 == NULL) {
1577 kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL);
1578 if (devpriv->ai_buf0 == NULL)
1582 ret = comedi_alloc_subdevices(dev, 4);
1586 /* analog input subdevice */
1587 s = &dev->subdevices[0];
1588 dev->read_subdev = s;
1589 s->type = COMEDI_SUBD_AI;
1590 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ;
1591 if (thisboard->common)
1592 s->subdev_flags |= SDF_COMMON;
1593 s->n_chan = thisboard->qram_len;
1594 s->len_chanlist = thisboard->qram_len;
1595 s->maxdata = (1 << thisboard->resolution) - 1;
1596 s->range_table = thisboard->range_ai;
1597 s->do_cmd = das1800_ai_do_cmd;
1598 s->do_cmdtest = das1800_ai_do_cmdtest;
1599 s->insn_read = das1800_ai_rinsn;
1600 s->poll = das1800_ai_poll;
1601 s->cancel = das1800_cancel;
1604 s = &dev->subdevices[1];
1605 if (thisboard->ao_ability == 1) {
1606 s->type = COMEDI_SUBD_AO;
1607 s->subdev_flags = SDF_WRITABLE;
1608 s->n_chan = thisboard->ao_n_chan;
1609 s->maxdata = (1 << thisboard->resolution) - 1;
1610 s->range_table = &range_bipolar10;
1611 s->insn_write = das1800_ao_winsn;
1613 s->type = COMEDI_SUBD_UNUSED;
1617 s = &dev->subdevices[2];
1618 s->type = COMEDI_SUBD_DI;
1619 s->subdev_flags = SDF_READABLE;
1622 s->range_table = &range_digital;
1623 s->insn_bits = das1800_di_rbits;
1626 s = &dev->subdevices[3];
1627 s->type = COMEDI_SUBD_DO;
1628 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
1629 s->n_chan = thisboard->do_n_chan;
1631 s->range_table = &range_digital;
1632 s->insn_bits = das1800_do_wbits;
1634 das1800_cancel(dev, dev->read_subdev);
1636 /* initialize digital out channels */
1637 outb(0, dev->iobase + DAS1800_DIGITAL);
1639 /* initialize analog out channels */
1640 if (thisboard->ao_ability == 1) {
1641 /* select 'update' dac channel for baseAddress + 0x0 */
1642 outb(DAC(thisboard->ao_n_chan - 1),
1643 dev->iobase + DAS1800_SELECT);
1644 outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);
1650 static void das1800_detach(struct comedi_device *dev)
1652 struct das1800_private *devpriv = dev->private;
1656 free_dma(devpriv->dma0);
1658 free_dma(devpriv->dma1);
1659 kfree(devpriv->ai_buf0);
1660 kfree(devpriv->ai_buf1);
1661 if (devpriv->iobase2)
1662 release_region(devpriv->iobase2, DAS1800_SIZE);
1664 comedi_legacy_detach(dev);
1667 static struct comedi_driver das1800_driver = {
1668 .driver_name = "das1800",
1669 .module = THIS_MODULE,
1670 .attach = das1800_attach,
1671 .detach = das1800_detach,
1672 .num_names = ARRAY_SIZE(das1800_boards),
1673 .board_name = &das1800_boards[0].name,
1674 .offset = sizeof(struct das1800_board),
1676 module_comedi_driver(das1800_driver);
1678 MODULE_AUTHOR("Comedi http://www.comedi.org");
1679 MODULE_DESCRIPTION("Comedi low-level driver");
1680 MODULE_LICENSE("GPL");