-// *INDENT-OFF*
/*
- * module/pcl812.c
+ * comedi/drivers/pcl812.c
+ *
+ * Author: Michal Dobes <majkl@tesnet.cz>
+ *
* hardware driver for Advantech cards
- * card: PCL-812PG, PCL-813B
- * driver: pcl812pg, pcl813b
- *
- * Michal Dobes <majkl@tesnet.cz>
- * Based on 711.c
- *
- * Options for PCL-812PG:
+ * card: PCL-812, PCL-812PG, PCL-813, PCL-813B
+ * driver: pcl812, pcl812pg, pcl813, pcl813b
+ * and for ADlink cards
+ * card: ACL-8112DG, ACL-8112HG, ACL-8112PG, ACL-8113, ACL-8216
+ * driver: acl8112dg, acl8112hg, acl8112pg, acl8113, acl8216
+ * and for ICP DAS cards
+ * card: ISO-813, A-821PGH, A-821PGL, A-821PGL-NDA, A-822PGH, A-822PGL,
+ * driver: iso813, a821pgh, a-821pgl, a-821pglnda, a822pgh, a822pgl,
+ * card: A-823PGH, A-823PGL, A-826PG
+ * driver: a823pgh, a823pgl, a826pg
+ *
+ * Options for PCL-812:
* [0] - IO Base
* [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
- * [2] - 0=trigger source is internal 8253 with 2MHz clock
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0=trigger source is internal 8253 with 2MHz clock
* 1=trigger source is external
- * [3] - 0=A/D have max +/-5V input
+ * [4] - 0=A/D input range is +/-10V
+ * 1=A/D input range is +/-5V
+ * 2=A/D input range is +/-2.5V
+ * 3=A/D input range is +/-1.25V
+ * 4=A/D input range is +/-0.625V
+ * 5=A/D input range is +/-0.3125V
+ * [5] - 0=D/A outputs 0-5V (internal reference -5V)
+ * 1=D/A outputs 0-10V (internal reference -10V)
+ * 2=D/A outputs unknow (external reference)
+ *
+ * Options for PCL-812PG, ACL-8112PG:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0=trigger source is internal 8253 with 2MHz clock
+ * 1=trigger source is external
+ * [4] - 0=A/D have max +/-5V input
* 1=A/D have max +/-10V input
- * [4] - 0=D/A outputs 0-5V (internal reference -5V)
+ * [5] - 0=D/A outputs 0-5V (internal reference -5V)
+ * 1=D/A outputs 0-10V (internal reference -10V)
+ * 2=D/A outputs unknow (external reference)
+ *
+ * Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0=trigger source is internal 8253 with 2MHz clock
+ * 1=trigger source is external
+ * [4] - 0=A/D channels are S.E.
+ * 1=A/D channels are DIFF
+ * [5] - 0=D/A outputs 0-5V (internal reference -5V)
* 1=D/A outputs 0-10V (internal reference -10V)
* 2=D/A outputs unknow (external reference)
*
+ * Options for A-821PGL/PGH:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - 0=A/D channels are S.E.
+ * 1=A/D channels are DIFF
+ * [3] - 0=D/A output 0-5V (internal reference -5V)
+ * 1=D/A output 0-10V (internal reference -10V)
+ *
+ * Options for A-821PGL-NDA:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - 0=A/D channels are S.E.
+ * 1=A/D channels are DIFF
+ *
+ * Options for PCL-813:
+ * [0] - IO Base
+ *
* Options for PCL-813B:
* [0] - IO Base
* [1] - 0= bipolar inputs
* 1= unipolar inputs
- * [2] - max number of samples in ai_mode0 (defaul=1scan)
- *
+ *
+ * Options for ACL-8113, ISO-813:
+ * [0] - IO Base
+ * [1] - 0= 10V bipolar inputs
+ * 1= 10V unipolar inputs
+ * 2= 20V bipolar inputs
+ * 3= 20V unipolar inputs
*
*/
#include <linux/comedidev.h>
#include "8253.h"
-/* #define MD_DEBUG */
-#define boardPCL812PG 0
-#define boardPCL813B 1
+#undef PCL812_EXTDEBUG /* if this is defined then a lot of messages is printed */
-#define PCLx1x_RANGE 16
-#define PCL812_CLRINT 8
-#define PCL812_GAIN 9
-#define PCL812_MUX 10
-#define PCL812_MODE 11
-#define PCL812_CNTENABLE 10
-#define PCL812_SOFTTRIG 12
-#define PCL812_CTR0 0
-#define PCL812_CTR1 1
-#define PCL812_CTR2 2
-#define PCL812_CTRCTL 3
+// hardware types of the cards
+#define boardPCL812PG 0 /* and ACL-8112PG */
+#define boardPCL813B 1
+#define boardPCL812 2
+#define boardPCL813 3
+#define boardISO813 5
+#define boardACL8113 6
+#define boardACL8112 7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */
+#define boardACL8216 8 /* and ICP DAS A-826PG */
+#define boardA821 9 /* PGH, PGL, PGL/NDA versions */
-#define PCL812_AD_LO 4
-#define PCL812_AD_HI 5
-#define PCL812_DA1_LO 4
-#define PCL812_DA1_HI 5
-#define PCL812_DA2_LO 6
-#define PCL812_DA2_HI 7
-#define PCL812_DI_LO 6
-#define PCL812_DI_HI 7
-#define PCL812_DO_LO 13
-#define PCL812_DO_HI 14
+#define PCLx1x_IORANGE 16
-#define PCL812_DRDY 0x10
+#define PCL812_CTR0 0
+#define PCL812_CTR1 1
+#define PCL812_CTR2 2
+#define PCL812_CTRCTL 3
+#define PCL812_AD_LO 4
+#define PCL812_DA1_LO 4
+#define PCL812_AD_HI 5
+#define PCL812_DA1_HI 5
+#define PCL812_DA2_LO 6
+#define PCL812_DI_LO 6
+#define PCL812_DA2_HI 7
+#define PCL812_DI_HI 7
+#define PCL812_CLRINT 8
+#define PCL812_GAIN 9
+#define PCL812_MUX 10
+#define PCL812_MODE 11
+#define PCL812_CNTENABLE 10
+#define PCL812_SOFTTRIG 12
+#define PCL812_DO_LO 13
+#define PCL812_DO_HI 14
-#define AI_LEN_CHANLIST 16
+#define PCL812_DRDY 0x10 /* =0 data ready */
-/*
- For PCL-813B:
- I don't know if timeouts which are specified at a documentation
- are miliseconds or microseconds. If your card don't work properly then
- undef next #define.
-*/
-#define PCL813_MICROSECS
+#define ACL8216_STATUS 8 /* 5. bit signalize data ready */
-#define INT_TYPE_AI1_INT 1
-/* #define INT_TYPE_AI1_DMA 2 */
-#define INT_TYPE_AI3_INT 3
-/* #define INT_TYPE_AI3_DMA 4 */
+#define ACL8216_DRDY 0x20 /* =0 data ready */
+
+#define MAX_CHANLIST_LEN 256 /* length of scan list */
static comedi_lrange range_pcl812pg_ai = { 5, {
BIP_RANGE(5),
BIP_RANGE(1.25),
BIP_RANGE(0.625),
}};
+static comedi_lrange range812_bipolar1_25 = { 1, {
+ BIP_RANGE(1.25),
+}};
+static comedi_lrange range812_bipolar0_625 = { 1, {
+ BIP_RANGE(0.625),
+}};
+static comedi_lrange range812_bipolar0_3125 = { 1, {
+ BIP_RANGE(0.3125),
+}};
static comedi_lrange range_pcl813b_ai = { 4, {
BIP_RANGE(5),
BIP_RANGE(2.5),
UNI_RANGE(2.5),
UNI_RANGE(1.25),
}};
+static comedi_lrange range_iso813_1_ai = { 5, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ BIP_RANGE(0.3125),
+}};
+static comedi_lrange range_iso813_1_2_ai = { 5, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ UNI_RANGE(0.625),
+}};
+static comedi_lrange range_iso813_2_ai = { 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+}};
+static comedi_lrange range_iso813_2_2_ai = { 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+}};
+static comedi_lrange range_acl8113_1_ai = { 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+}};
+static comedi_lrange range_acl8113_1_2_ai = { 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+}};
+static comedi_lrange range_acl8113_2_ai = { 3, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+}};
+static comedi_lrange range_acl8113_2_2_ai = { 3, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+}};
+static comedi_lrange range_acl8112dg_ai = { 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ BIP_RANGE(10),
+}};
+static comedi_lrange range_acl8112hg_ai = { 12, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01),
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.01),
+}};
+static comedi_lrange range_a821pgh_ai = { 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005),
+}};
static int pcl812_attach(comedi_device *dev,comedi_devconfig *it);
static int pcl812_detach(comedi_device *dev);
-static int i8253_osc_base = 500; /* 2 Mhz */
-
typedef struct {
- char *name;
- int is_812pg;
- int is_813b;
- int n_ranges;
- int n_aichan;
- int ai_maxsample;
- int n_aochan;
- int n_dichan;
- int n_dochan;
- comedi_lrange *ai_range_type;
- comedi_lrange *ao_range_type;
- int io_range;
- unsigned int IRQbits;
-#ifdef USE_DMA
- unsigned int DMAbits;
-#endif
+ char *name; // driver name
+ int board_type; // type of this board
+ int n_aichan; // num of AI chans in S.E.
+ int n_aichan_diff; // DIFF num of chans
+ int n_aochan; // num of DA chans
+ int n_dichan; // DI and DO chans
+ int n_dochan;
+ int ai_maxdata; // AI resolution
+ unsigned int ai_ns_min; // max sample speed of card v ns
+ unsigned int i8254_osc_base; // clock base
+ comedi_lrange *rangelist_ai; // rangelist for A/D
+ comedi_lrange *rangelist_ao; // rangelist for D/A
+ unsigned int IRQbits; // allowed IRQ
+ unsigned char DMAbits; // allowed DMA chans
+ unsigned char io_range; // iorange for this board
+ unsigned char haveMPC508; // 1=board use MPC508A multiplexor
} boardtype;
static boardtype boardtypes[] =
{
- {
- name: "pcl812pg",
- is_812pg: 1,
- n_ranges: 5,
- n_aichan: 16,
- ai_maxsample: 30,
- n_aochan: 2,
- n_dichan: 16,
- n_dochan: 16,
- ai_range_type: &range_pcl812pg_ai,
- ao_range_type: &range_unipolar5,
- io_range: PCLx1x_RANGE,
- IRQbits: 0xdcfc,
-#ifdef USE_DMA
- DMAbits: 0x00,
-#endif
- },
- {
- name: "pcl813b",
- is_813b: 1,
- n_ranges: 4,
- n_aichan: 32,
- ai_maxsample: 25,
- n_aochan: 0,
- n_dichan: 0,
- n_dochan: 0,
- ai_range_type: &range_pcl813b_ai,
- ao_range_type: NULL,
- io_range: PCLx1x_RANGE,
- IRQbits: 0x0000
-#ifdef USE_DMA
- DMAbits: 0x00,
-#endif
- },
+ {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
+ 33000, 500, &range_bipolar10, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+ 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+ 10000, 500, &range_pcl813b_ai, &range_unipolar5,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
+ 10000, 500, &range_pcl813b_ai, NULL,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+ 10000, 500, &range_a821pgh_ai, &range_unipolar5,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_pcl813b_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_pcl813b_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_acl8113_1_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_iso813_1_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+ 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+ 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
};
#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
COMEDI_INITCLEANUP(driver_pcl812);
typedef struct {
-#ifdef USE_DMA
- int dma;
- unsigned long dmabuf[2];
- unsigned int dmapages[2];
- unsigned int hwdmaptr[2];
- unsigned int hwdmasize[2];
- int next_dma_buf;
- unsigned long dma_runs_to_end;
-#endif
- int irq_free;
- int irq_blocked;
- int irq_was_now_closed;
- int max_812_ai_mode0_samples;
- int max_812_ai_mode0_rangewait;
- int max_812_ai_mode0_chanset;
- int max_812_ai_mode0_convstart;
- int int812_mode; /*1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
- //int int13_act_ptr;
- int int13_act_scan;
- unsigned int chanlist[AI_LEN_CHANLIST];
- lsampl_t ao_readback[2];
-
+ unsigned char valid; // =1 device is OK
+ unsigned char dma; // >0 use dma ( usedDMA channel)
+ unsigned char use_diff; // =1 diff inputs
+ unsigned char use_MPC; // 1=board uses MPC508A multiplexor
+ unsigned char use_ext_trg; // 1=board uses external trigger
+ unsigned char range_correction; // =1 we must add 1 to range number
+ unsigned char old_chan_reg; // lastly used chan/gain pair
+ unsigned char old_gain_reg;
+ unsigned char mode_reg_int; // there is stored INT number for some card
+ unsigned char ai_neverending; // =1 we do unlimited AI
+ unsigned char ai_eos; // 1=EOS wake up
+ unsigned char ai_dma; // =1 we use DMA
+ unsigned int ai_poll_ptr; // how many sampes transfer poll
+ unsigned int ai_scans; // len of scanlist
+ unsigned int ai_act_scan; // how many scans we finished
+ unsigned int ai_chanlist[MAX_CHANLIST_LEN];// our copy of channel/range list
+ unsigned int ai_n_chan; // how many channels is measured
+ unsigned int ai_flags; // flaglist
+ unsigned int ai_data_len; // len of data buffer
+ sampl_t *ai_data; // data buffer
+ unsigned int ai_is16b; // =1 we have 16 bit card
+ unsigned long dmabuf[2]; // PTR to DMA buf
+ unsigned int dmapages[2]; // how many pages we have allocated
+ unsigned int hwdmaptr[2]; // HW PTR to DMA buf
+ unsigned int hwdmasize[2]; // DMA buf size in bytes
+ unsigned int dmabytestomove[2]; // how many bytes DMA transfer
+ int next_dma_buf; // which buffer is next to use
+ unsigned int dma_runs_to_end; // how many times we must switch DMA buffers
+ unsigned int last_dma_run; // how many bytes to transfer on last DMA buffer
+ unsigned int max_812_ai_mode0_rangewait;// setling time for gain
+ lsampl_t ao_readback[2]; // data for AO readback
} pcl812_private;
#define devpriv ((pcl812_private *)dev->private)
-// *INDENT-ON*
/*
==============================================================================
- ANALOG INPUT MODE0, 812pg and 813b card
+*/
+void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);
+void setup_range_channel(comedi_device * dev, comedi_subdevice * s,
+ unsigned int rangechan, char wait);
+int pcl812_ai_cancel(comedi_device * dev, comedi_subdevice * s);
+/*
+==============================================================================
*/
static int pcl812_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
int n;
int timeout, hi;
- outb(1, dev->iobase + PCL812_MODE); /* select software trigger */
-
- /* select gain */
- outb(CR_RANGE(insn->chanspec), dev->iobase + PCL812_GAIN);
- /* select channel */
- outb(CR_CHAN(insn->chanspec), dev->iobase + PCL812_MUX);
-#define max(a,b) ((a>b)?(a):(b))
- udelay(max(devpriv->max_812_ai_mode0_rangewait,
- devpriv->max_812_ai_mode0_chanset));
+ outb(devpriv->mode_reg_int|1, dev->iobase + PCL812_MODE); /* select software trigger */
+ setup_range_channel(dev, s, insn->chanspec, 1); // select channel and renge
for(n=0;n<insn->n;n++){
outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */
- udelay(devpriv->max_812_ai_mode0_convstart);
- timeout = 20; /* wait max 100us, it must finish under 33us */
+ udelay(5);
+ timeout = 50; /* wait max 50us, it must finish under 33us */
while (timeout--) {
hi = inb(dev->iobase + PCL812_AD_HI);
if (!(hi & PCL812_DRDY))
goto conv_finish;
+ udelay(1);
}
- rt_printk("comedi%d: pcl812: (%s at 0x%x) A/D mode0 timeout\n", dev->minor, dev->board_name, dev->iobase);
- outb(0, dev->iobase + PCL812_MODE);
+ rt_printk("comedi%d: pcl812: (%s at 0x%x) A/D insn read timeout\n", dev->minor, dev->board_name, dev->iobase);
+ outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE);
return -ETIME;
conv_finish:
data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
}
+ outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE);
+ return n;
+}
+
+/*
+==============================================================================
+*/
+static int acl8216_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
+ comedi_insn *insn,lsampl_t *data)
+{
+ int n;
+ int timeout;
+
+ outb(1, dev->iobase + PCL812_MODE); /* select software trigger */
+ setup_range_channel(dev, s, insn->chanspec, 1); // select channel and renge
+ for(n=0;n<insn->n;n++){
+ outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */
+ udelay(5);
+ timeout = 50; /* wait max 50us, it must finish under 33us */
+ while (timeout--) {
+ if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY))
+ goto conv_finish;
+ udelay(1);
+ }
+ rt_printk("comedi%d: pcl812: (%s at 0x%x) A/D insn read timeout\n", dev->minor, dev->board_name, dev->iobase);
+ outb(0, dev->iobase + PCL812_MODE);
+ return -ETIME;
+
+ conv_finish:
+ data[n] = (inb(dev->iobase + PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO);
+ }
outb(0, dev->iobase + PCL812_MODE);
return n;
}
/*
==============================================================================
- ANALOG OUTPUT MODE0, 812pg card
- only one sample per call is supported
*/
static int pcl812_ao_insn_write(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
return i;
}
+/*
+==============================================================================
+*/
static int pcl812_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
{
/*
==============================================================================
- DIGITAL INPUT MODE0, 812pg card
-
- only one sample per call is supported
*/
static int pcl812_di_insn_bits(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
/*
==============================================================================
- DIGITAL OUTPUT MODE0, 812pg card
-
- only one sample per call is supported
*/
static int pcl812_do_insn_bits(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
return 2;
}
+#ifdef PCL812_EXTDEBUG
/*
==============================================================================
- analog input interrupt mode 1 & 3, 812pg card
- one sample per interrupt version
*/
-static void interrupt_pcl812_ai_mode13_int(int irq, void *d, struct pt_regs *regs)
+void pcl812_cmdtest_out(int e,comedi_cmd *cmd) {
+ rt_printk("pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n",e,cmd->start_src,cmd->scan_begin_src,cmd->convert_src);
+ rt_printk("pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n",e,cmd->start_arg,cmd->scan_begin_arg,cmd->convert_arg);
+ rt_printk("pcl812 e=%d stopsrc=%x scanend=%x\n",e,cmd->stop_src,cmd->scan_end_src);
+ rt_printk("pcl812 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",e,cmd->stop_arg,cmd->scan_end_arg,cmd->chanlist_len);
+}
+#endif
+
+/*
+==============================================================================
+*/
+static int pcl812_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
{
+ int err=0;
+ int tmp,divisor1,divisor2;
- int hi;
- comedi_device *dev = d;
- comedi_subdevice *s = dev->subdevices + 0;
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n");
+ pcl812_cmdtest_out(-1, cmd);
+#endif
+ /* step 1: make sure trigger sources are trivially valid */
- int timeout = 20; /* wait max 100us, it must finish under 33us */
- while (timeout--) {
- hi = inb(dev->iobase + PCL812_AD_HI);
- if (!(hi & PCL812_DRDY))
- goto conv_finish;
- udelay(5);
- }
- hi = inb(dev->iobase + PCL812_AD_LO);
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- rt_printk("comedi%d: pcl812: (%s at 0x%x) A/D mode1/3 IRQ without DRDY!\n", dev->minor, dev->board_name, dev->iobase);
- comedi_done(dev,s);
- return;
+ tmp=cmd->start_src;
+ cmd->start_src &= TRIG_NOW;
+ if(!cmd->start_src || tmp!=cmd->start_src)err++;
- conv_finish:
+ tmp=cmd->scan_begin_src;
+ cmd->scan_begin_src &= TRIG_FOLLOW;
+ if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
- *(sampl_t *)(s->async->data+s->async->buf_int_ptr) =
- ((hi << 8) | inb(dev->iobase + PCL812_AD_LO)) & 0xfff;
- s->async->buf_int_ptr+=sizeof(sampl_t);
+ tmp=cmd->convert_src;
+ if (devpriv->use_ext_trg) { cmd->convert_src &= TRIG_EXT; }
+ else { cmd->convert_src &= TRIG_TIMER; }
+ if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
+ tmp=cmd->scan_end_src;
+ cmd->scan_end_src &= TRIG_COUNT;
+ if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
- s->async->buf_int_count += sizeof(sampl_t);
+ tmp=cmd->stop_src;
+ cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
+ if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
- s->async->cur_chan++;
- if (s->async->cur_chan >= s->async->cur_chanlist_len) { /* one scan done */
- s->async->cur_chan=0;
-#if 0
- /* this uses comedi_eos and comedi_bufcheck incorrectly */
- if (devpriv->cur_flags & TRIG_WAKE_EOS) {
- comedi_eos(dev, s);
- } else {
- comedi_bufcheck(dev, s);
+ if(err) {
+#ifdef PCL812_EXTDEBUG
+ pcl812_cmdtest_out(1, cmd);
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n",err);
+#endif
+ return 1;
+ }
+
+ /* step 2: make sure trigger sources are unique and mutually compatible */
+
+ if(cmd->start_src!=TRIG_NOW) {
+ cmd->start_src=TRIG_NOW;
+ err++;
+ }
+
+ if(cmd->scan_begin_src!=TRIG_FOLLOW) {
+ cmd->scan_begin_src=TRIG_FOLLOW;
+ err++;
+ }
+
+ if (devpriv->use_ext_trg) {
+ if(cmd->convert_src!=TRIG_EXT) {
+ cmd->convert_src=TRIG_EXT;
+ err++;
}
-#else
- comedi_bufcheck(dev, s);
+ } else {
+ if(cmd->convert_src!=TRIG_TIMER) {
+ cmd->convert_src=TRIG_TIMER;
+ err++;
+ }
+ }
+
+ if(cmd->scan_end_src!=TRIG_COUNT) {
+ cmd->scan_end_src=TRIG_COUNT;
+ err++;
+ }
+
+ if(cmd->stop_src!=TRIG_NONE &&
+ cmd->stop_src!=TRIG_COUNT) err++;
+
+ if(err) {
+#ifdef PCL812_EXTDEBUG
+ pcl812_cmdtest_out(2, cmd);
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n",err);
#endif
- devpriv->int13_act_scan--;
+ return 2;
}
- outb(CR_RANGE(devpriv->chanlist[s->async->cur_chan]), dev->iobase + PCL812_GAIN); /* select next gain */
- outb(CR_CHAN(devpriv->chanlist[s->async->cur_chan]), dev->iobase + PCL812_MUX); /* select next channel */
- if (s->async->buf_int_ptr >= s->async->data_len) { /* buffer rollover */
- s->async->buf_int_ptr = 0;
- //devpriv->int13_act_ptr=0;
- comedi_eobuf(dev, s);
+ /* step 3: make sure arguments are trivially compatible */
+
+ if(cmd->start_arg!=0){
+ cmd->start_arg=0;
+ err++;
+ }
+
+ if(cmd->scan_begin_arg!=0){
+ cmd->scan_begin_arg=0;
+ err++;
+ }
+
+ if(cmd->convert_src==TRIG_TIMER){
+ if(cmd->convert_arg<this_board->ai_ns_min){
+ cmd->convert_arg=this_board->ai_ns_min;
+ err++;
+ }
+ } else { /* TRIG_EXT */
+ if(cmd->convert_arg!=0){
+ cmd->convert_arg=0;
+ err++;
+ }
}
- if (devpriv->int13_act_scan == 0) { /* all data sampled */
- outb(0, dev->iobase + PCL812_MODE); /* Stop A/D */
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- if (devpriv->int812_mode == 1) {
- /* Stop pacer */
- outb(0xb4, dev->iobase + PCL812_CTRCTL);
- outb(0x74, dev->iobase + PCL812_CTRCTL);
+ if(!cmd->chanlist_len){
+ cmd->chanlist_len=1;
+ err++;
+ }
+ if(cmd->chanlist_len>MAX_CHANLIST_LEN){
+ cmd->chanlist_len=this_board->n_aichan;
+ err++;
+ }
+ if(cmd->scan_end_arg!=cmd->chanlist_len){
+ cmd->scan_end_arg=cmd->chanlist_len;
+ err++;
+ }
+ if(cmd->stop_src==TRIG_COUNT){
+ if(!cmd->stop_arg){
+ cmd->stop_arg=1;
+ err++;
+ }
+ } else { /* TRIG_NONE */
+ if(cmd->stop_arg!=0){
+ cmd->stop_arg=0;
+ err++;
}
- s->busy = 0;
- devpriv->irq_blocked = 0;
- devpriv->int812_mode = 0;
- devpriv->irq_was_now_closed = 1;
- /* printk("comedi_done\n"); */
- comedi_done(dev, s);
}
-}
+ if(err) {
+#ifdef PCL812_EXTDEBUG
+ pcl812_cmdtest_out(3, cmd);
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n",err);
+#endif
+ return 3;
+ }
+
+ /* step 4: fix up any arguments */
+
+ if(cmd->convert_src==TRIG_TIMER){
+ tmp=cmd->convert_arg;
+ i8253_cascade_ns_to_timer(this_board->i8254_osc_base,&divisor1,&divisor2,&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
+ if(cmd->convert_arg<this_board->ai_ns_min)
+ cmd->convert_arg=this_board->ai_ns_min;
+ if(tmp!=cmd->convert_arg)err++;
+ }
+
+ if(err) {
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n",err);
+#endif
+ return 4;
+ }
+
+ return 0;
+}
/*
==============================================================================
- INT procedure
*/
-static void interrupt_pcl812(int irq, void *d, struct pt_regs *regs)
+static int pcl812_ai_cmd(comedi_device *dev,comedi_subdevice *s)
{
+ unsigned int divisor1, divisor2, i, dma_flags, bytes;
+ comedi_cmd *cmd=&s->async->cmd;
+
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
+#endif
- comedi_device *dev = d;
+ if(cmd->start_src!=TRIG_NOW) return -EINVAL;
+ if(cmd->scan_begin_src!=TRIG_FOLLOW) return -EINVAL;
+ if (devpriv->use_ext_trg) {
+ if(cmd->convert_src!=TRIG_EXT) return -EINVAL;
+ } else {
+ if(cmd->convert_src!=TRIG_TIMER) return -EINVAL;
+ }
+ if(cmd->scan_end_src!=TRIG_COUNT) return -EINVAL;
+ if(cmd->scan_end_arg!=cmd->chanlist_len) return -EINVAL;
+ if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL;
+
+ if (cmd->convert_src==TRIG_TIMER) {
+ if(cmd->convert_arg<this_board->ai_ns_min) cmd->convert_arg=this_board->ai_ns_min;
+ i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
+ &divisor1, &divisor2, &cmd->convert_arg,
+ cmd->flags&TRIG_ROUND_MASK);
+ }
- if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) | (!devpriv->int812_mode)) {
- if (devpriv->irq_was_now_closed) {
- devpriv->irq_was_now_closed = 0;
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- rt_printk("comedi%d: pcl812: (%s at 0x%x) too much IRQs!\n", dev->minor, dev->board_name, dev->iobase);
- return;
- }
- rt_printk("comedi%d: pcl812: (%s at 0x%x) bad IRQ!\n", dev->minor, dev->board_name, dev->iobase);
- return;
+ start_pacer(dev, -1, 0, 0); // stop pacer
+
+ devpriv->ai_n_chan=cmd->chanlist_len;
+ memcpy(devpriv->ai_chanlist,cmd->chanlist,sizeof(unsigned int)*cmd->scan_end_arg);
+ setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); // select first channel and range
+
+ if (devpriv->dma) { // check if we can use DMA transfer
+ devpriv->ai_dma=1;
+ for (i=1; i<devpriv->ai_n_chan; i++)
+ if (devpriv->ai_chanlist[0]!=devpriv->ai_chanlist[i]) {
+ devpriv->ai_dma=0; // we cann't use DMA :-(
+ break;
+ }
+ } else devpriv->ai_dma=0;
+
+ devpriv->ai_flags=cmd->flags;
+ devpriv->ai_data_len=s->async->data_len;
+ devpriv->ai_data=s->async->data;
+ if (cmd->stop_src==TRIG_COUNT) { devpriv->ai_scans=cmd->stop_arg; devpriv->ai_neverending=0; }
+ else { devpriv->ai_scans=0; devpriv->ai_neverending=1; }
+
+ devpriv->ai_act_scan=0;
+ devpriv->ai_poll_ptr=0;
+ s->async->cur_chan=0;
+
+ if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { // don't we want wake up every scan?
+ devpriv->ai_eos=1;
+ if (devpriv->ai_n_chan==1)
+ devpriv->ai_dma=0; // DMA is useless for this situation
}
- switch (devpriv->int812_mode) {
- case INT_TYPE_AI1_INT:
- interrupt_pcl812_ai_mode13_int(irq, d, regs);
- return;
- case INT_TYPE_AI3_INT:
- interrupt_pcl812_ai_mode13_int(irq, d, regs);
- return;
-#if USE_DMA
- case INT_TYPE_AI1_DMA:
- interrupt_pcl812_ai_mode13_dma(irq, d, regs);
- return;
- case INT_TYPE_AI3_DMA:
- interrupt_pcl812_ai_mode13_dma(irq, d, regs);
- return;
+ if (devpriv->ai_dma) {
+ if (devpriv->ai_eos) { // we use EOS, so adapt DMA buffer to one scan
+ devpriv->dmabytestomove[0]=devpriv->ai_n_chan*sizeof(sampl_t);
+ devpriv->dmabytestomove[1]=devpriv->ai_n_chan*sizeof(sampl_t);
+ devpriv->dma_runs_to_end=1;
+ } else {
+ devpriv->dmabytestomove[0]=devpriv->hwdmasize[0];
+ devpriv->dmabytestomove[1]=devpriv->hwdmasize[1];
+ if (devpriv->ai_data_len<devpriv->hwdmasize[0])
+ devpriv->dmabytestomove[0]=devpriv->ai_data_len;
+ if (devpriv->ai_data_len<devpriv->hwdmasize[1])
+ devpriv->dmabytestomove[1]=devpriv->ai_data_len;
+ if (devpriv->ai_neverending) {
+ devpriv->dma_runs_to_end=1;
+ } else {
+ bytes=devpriv->ai_n_chan*devpriv->ai_scans*sizeof(sampl_t); // how many samples we must transfer?
+ devpriv->dma_runs_to_end=bytes / devpriv->dmabytestomove[0]; // how many DMA pages we must fill
+ devpriv->last_dma_run=bytes % devpriv->dmabytestomove[0]; //on last dma transfer must be moved
+ if (devpriv->dma_runs_to_end==0)
+ devpriv->dmabytestomove[0]=devpriv->last_dma_run;
+ devpriv->dma_runs_to_end--;
+ }
+ }
+ if (devpriv->dmabytestomove[0]>devpriv->hwdmasize[0]) {
+ devpriv->dmabytestomove[0]=devpriv->hwdmasize[0];
+ devpriv->ai_eos=0;
+ }
+ if (devpriv->dmabytestomove[1]>devpriv->hwdmasize[1]) {
+ devpriv->dmabytestomove[1]=devpriv->hwdmasize[1];
+ devpriv->ai_eos=0;
+ }
+ devpriv->next_dma_buf=0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags=claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n",
+ devpriv->dma,devpriv->hwdmaptr[0],devpriv->hwdmaptr[1],
+ devpriv->dmabytestomove[0],devpriv->dmabytestomove[1],
+ devpriv->ai_eos);
#endif
}
+
+ switch (cmd->convert_src) {
+ case TRIG_TIMER:
+ start_pacer(dev, 1, divisor1, divisor2);
+ break;
+ }
+
+ if (devpriv->ai_dma) {
+ outb(devpriv->mode_reg_int|2, dev->iobase + PCL812_MODE); // let's go!
+ } else {
+ outb(devpriv->mode_reg_int|6, dev->iobase + PCL812_MODE); // let's go!
+ }
+
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
+#endif
+
+ return 0;
}
/*
==============================================================================
- ANALOG INPUT MODE 1, 812pg card
- interrupt pacer pooling
*/
-#ifdef CONFIG_COMEDI_TRIG
-static int pcl812_ai_mode1_int(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
+static void interrupt_pcl812_ai_int(int irq, void *d, struct pt_regs *regs)
{
- int timer1,timer2;
+ char err=1;
+ unsigned int mask, timeout;
+ comedi_device *dev = d;
+ comedi_subdevice *s = dev->subdevices + 0;
- /*
- * Set timers
- * timer chip is an 8253, with timers 1 and 2
- * cascaded
- * 0x74 = Select Counter 1 | LSB/MSB | Mode=2 | Binary
- * Mode 2 = Rate generator
- *
- * 0xb4 = Select Counter 2 | LSB/MSB | Mode=2 | Binary
- */
+ s->async->events = 0;
- i8253_cascade_ns_to_timer(i8253_osc_base,&timer1,&timer2,&it->trigvar,TRIG_ROUND_NEAREST);
+ timeout = 50; /* wait max 50us, it must finish under 33us */
+ if (devpriv->ai_is16b) {
+ mask=0xffff;
+ while (timeout--) {
+ if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) {
+ err=0; break;
+ }
+ udelay(1);
+ }
+ } else {
+ mask=0x0fff;
+ while (timeout--) {
+ if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) {
+ err=0; break;
+ }
+ udelay(1);
+ }
+ }
+
+ if (err) {
+ rt_printk("comedi%d: pcl812: (%s at 0x%x) A/D cmd IRQ without DRDY!\n", dev->minor, dev->board_name, dev->iobase);
+ pcl812_ai_cancel(dev,s);
+ s->async->events |= COMEDI_CB_EOA|COMEDI_CB_ERROR;
+ comedi_event(dev,s,s->async->events);
+ return;
+ }
- outb(0x74, dev->iobase + PCL812_CTRCTL);
- outb((timer1) & 0xff, dev->iobase + PCL812_CTR1);
- outb((timer1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
- outb(0xb4, dev->iobase + PCL812_CTRCTL);
- outb(timer2 & 0xff, dev->iobase + PCL812_CTR2);
- outb((timer2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
+ *(sampl_t *)(s->async->data+s->async->buf_int_ptr) =
+ ((inb(dev->iobase + PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO)) & mask;
- /* clear pending interrupts (just in case) */
- outb(0, dev->iobase + PCL812_CLRINT);
+ setup_range_channel(dev, s, devpriv->ai_chanlist[s->async->cur_chan], 0); // select channel and renge
- //devpriv->int13_act_ptr=0;
- devpriv->int13_act_scan = 0;
- devpriv->int812_mode = INT_TYPE_AI1_INT; /* analog in, mode 0, int driven */
- devpriv->irq_blocked = 1;
- devpriv->irq_was_now_closed = 0;
+ outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- memcpy(devpriv->chanlist,it->chanlist,sizeof(int)*it->n_chan);
+ s->async->buf_int_ptr+=sizeof(sampl_t);
+ s->async->buf_int_count+=sizeof(sampl_t);
- outb(6, dev->iobase + PCL812_MODE); /* Pacer+IRQ */
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= s->async->cur_chanlist_len) { /* one scan done */
+ s->async->cur_chan=0;
+ devpriv->ai_act_scan++;
+ if (devpriv->ai_eos)
+ s->async->events |= COMEDI_CB_EOS;
+ if (!(devpriv->ai_neverending))
+ if (devpriv->ai_act_scan>=devpriv->ai_scans) { /* all data sampled */
+ pcl812_ai_cancel(dev,s);
+ s->async->events |= COMEDI_CB_EOA;
+ }
+ }
+
+ if (s->async->buf_int_ptr >= s->async->data_len) { /* buffer rollover */
+ s->async->buf_int_ptr = 0;
+ s->async->events |= COMEDI_CB_EOBUF;
+ }
- return 0;
+ comedi_event(dev,s,s->async->events);
}
-#endif
/*
==============================================================================
- ANALOG INPUT MODE 1, 812pg card
*/
-#ifdef CONFIG_COMEDI_TRIG
-static int pcl812_ai_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
+static void transfer_from_dma_buf(comedi_device *dev,comedi_subdevice *s,
+ sampl_t *ptr, unsigned int bufptr, unsigned int len)
{
-
- if (!dev->irq)
- return -EINVAL;
- if (devpriv->irq_blocked)
- return -EBUSY;
- if (it->n_chan < 0)
- return -1;
-
-#ifdef USE_DMA
- if (devpriv->dma) { /* check if we can use DMA? */
- if (it->n_chan == 1) {
- return pcl812_ai_mode1_dma(dev, s, it); /* we scanning only one chan, we can */
- } else {
- fst = it->chanlist[0];
- for (i = 1; i < it->n_chan; i++) {
- if (fst != it->chanlist[0]) {
- i = -1;
+ unsigned int i;
+
+ s->async->events = 0;
+ for (i=len; i; i--) {
+ *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=ptr[bufptr++]; // get one sample
+
+ s->async->buf_int_ptr+=sizeof(sampl_t);
+ s->async->buf_int_count+=sizeof(sampl_t);
+
+ s->async->cur_chan++;
+ if(s->async->cur_chan>=s->async->cur_chanlist_len){
+ s->async->cur_chan=0;
+ devpriv->ai_act_scan++;
+ if (devpriv->ai_eos)
+ s->async->events |= COMEDI_CB_EOS;
+ if (!devpriv->ai_neverending)
+ if (devpriv->ai_act_scan>=devpriv->ai_scans) { /* all data sampled */
+ pcl812_ai_cancel(dev,s);
+ s->async->events |= COMEDI_CB_EOA;
break;
}
- }
- if (i == -1) {
- return pcl812_ai_mode1_int(dev, s, it);
- } else {
- return pcl812_ai_mode1_dma(dev, s, it);
- }
}
+
+ if (s->async->buf_int_ptr>=s->async->data_len) { /* buffer rollover */
+ s->async->buf_int_ptr=0;
+ s->async->events |= COMEDI_CB_EOBUF;
+ comedi_event(dev,s,s->async->events);
+ s->async->events = 0;
+ }
+
}
-#endif
- return pcl812_ai_mode1_int(dev, s, it); /* no, we can only int driven */
+
+ s->async->events |= COMEDI_CB_BLOCK;
+ comedi_event(dev,s,s->async->events);
}
+
+/*
+==============================================================================
+*/
+static void interrupt_pcl812_ai_dma(int irq, void *d, struct pt_regs *regs)
+{
+ comedi_device *dev = d;
+ comedi_subdevice *s = dev->subdevices + 0;
+ unsigned long dma_flags;
+ int len,bufptr;
+ sampl_t *ptr;
+
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
+#endif
+ ptr=(sampl_t *)devpriv->dmabuf[devpriv->next_dma_buf];
+ len=(devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr;
+
+ devpriv->next_dma_buf=1-devpriv->next_dma_buf;
+ disable_dma(devpriv->dma);
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags=claim_dma_lock();
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->ai_eos) {
+ set_dma_count(devpriv->dma, devpriv->dmabytestomove[devpriv->next_dma_buf]);
+ } else {
+ if (devpriv->dma_runs_to_end) { set_dma_count(devpriv->dma, devpriv->dmabytestomove[devpriv->next_dma_buf]); }
+ else { set_dma_count(devpriv->dma, devpriv->last_dma_run); }
+ devpriv->dma_runs_to_end--;
+ }
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
+
+ outb(0,dev->iobase+PCL812_CLRINT); /* clear INT request */
+
+ bufptr=devpriv->ai_poll_ptr;
+ devpriv->ai_poll_ptr=0;
+
+ transfer_from_dma_buf(dev, s, ptr, bufptr, len);
+
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
#endif
+}
/*
==============================================================================
- ANALOG INPUT MODE 3, 812pg card
*/
-#ifdef CONFIG_COMEDI_TRIG
-static int pcl812_ai_mode3_int(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
+static void interrupt_pcl812(int irq, void *d, struct pt_regs *regs)
{
+ comedi_device *dev = d;
- if (!dev->irq)
- return -EINVAL;
- if (devpriv->irq_blocked)
- return -EBUSY;
+ if (devpriv->ai_dma) { interrupt_pcl812_ai_dma(irq, d, regs); }
+ else { interrupt_pcl812_ai_int(irq, d, regs); };
- /* clear pending interrupts (just in case) */
- outb(0, dev->iobase + PCL812_CLRINT);
+}
- //devpriv->int13_act_ptr=0;
- devpriv->int13_act_scan = it->n;
- devpriv->int812_mode = 3; /* analog in, mode 3, int driven */
- devpriv->irq_blocked = 1;
+/*
+==============================================================================
+*/
+static int pcl812_ai_poll(comedi_device *dev,comedi_subdevice *s)
+{
+ unsigned long flags;
+ unsigned int top1,top2,i;
- memcpy(devpriv->chanlist,it->chanlist,sizeof(int)*it->n_chan);
+ if (!devpriv->ai_dma) return 0; // poll is valid only for DMA transfer
+
+ comedi_spin_lock_irqsave(&dev->spinlock,flags);
- outb(6, dev->iobase + PCL812_MODE); /* external trigger+IRQ */
+ for (i=0; i<10; i++) {
+ top1=get_dma_residue(devpriv->ai_dma); // where is now DMA
+ top2=get_dma_residue(devpriv->ai_dma);
+ if (top1==top2) break;
+ }
- return 0;
+ if (top1!=top2) {
+ comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
+ return 0;
+ }
+
+ top1=devpriv->dmabytestomove[1-devpriv->next_dma_buf]-top1; // where is now DMA in buffer
+ top1>>=1; // sample position
+ top2=top1-devpriv->ai_poll_ptr;
+ if (top2<1) { // no new samples
+ comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
+ return 0;
+ }
+
+ transfer_from_dma_buf(dev, s, (void *)devpriv->dmabuf[1-devpriv->next_dma_buf],
+ devpriv->ai_poll_ptr, top2);
+
+ devpriv->ai_poll_ptr=top1; // new buffer position
+
+ comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
+
+ return s->async->buf_int_count-s->async->buf_user_count;
}
+
+/*
+==============================================================================
+*/
+void setup_range_channel(comedi_device * dev, comedi_subdevice * s,
+ unsigned int rangechan, char wait)
+{
+ unsigned char chan_reg=CR_CHAN(rangechan); // normal board
+ unsigned char gain_reg=CR_RANGE(rangechan)+devpriv->range_correction; // gain index
+
+ if ((chan_reg==devpriv->old_chan_reg)&&(gain_reg==devpriv->old_gain_reg))
+ return; // we can return, no change
+
+ devpriv->old_chan_reg=chan_reg;
+ devpriv->old_gain_reg=gain_reg;
+
+ if (devpriv->use_MPC) {
+ if (devpriv->use_diff) {
+ chan_reg=chan_reg | 0x30; // DIFF inputs
+ } else {
+ if (chan_reg&0x80) {
+ chan_reg=chan_reg | 0x20; // SE inputs 8-15
+ } else {
+ chan_reg=chan_reg | 0x10; // SE inputs 0-7
+ }
+ }
+ }
+
+ outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */
+ outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */
+
+ if (wait) {
+ udelay(devpriv->max_812_ai_mode0_rangewait); // XXX this depends on selected range and can be very long for some high gain ranges!
+ }
+}
+
+
+/*
+==============================================================================
+*/
+void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2)
+{
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n",mode,divisor1,divisor2);
+#endif
+ outb(0xb4, dev->iobase + PCL812_CTRCTL);
+ outb(0x74, dev->iobase + PCL812_CTRCTL);
+ udelay(1);
+
+ if (mode==1) {
+ outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
+ outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
+ outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
+ outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
+ }
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: END: start_pacer(...)\n");
#endif
+}
/*
==============================================================================
- Free any resources that we have claimed
*/
static void free_resources(comedi_device * dev)
{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, this_board->io_range);
-#ifdef USE_DMA
if (dev->private) {
if (devpriv->dmabuf[0])
free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
if (devpriv->dma)
free_dma(devpriv->dma);
}
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, this_board->io_range);
+}
+
+/*
+==============================================================================
+*/
+int pcl812_ai_cancel(comedi_device * dev, comedi_subdevice * s)
+{
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
#endif
+ if (devpriv->ai_dma) disable_dma(devpriv->dma);
+ outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
+ outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE); /* Stop A/D */
+ start_pacer(dev,-1,0,0); // stop 8254
+ outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
+#endif
+ return 0;
}
/*
==============================================================================
- reset whole PCL-812 or PCL-813
*/
static void pcl812_reset(comedi_device * dev)
{
- if (this_board->is_812pg){
- outb(0, dev->iobase + PCL812_DA1_LO);
- outb(0, dev->iobase + PCL812_DA1_HI);
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: BGN: pcl812_reset(...)\n");
+#endif
+ outb(0, dev->iobase + PCL812_MUX);
+ outb(0+devpriv->range_correction, dev->iobase + PCL812_GAIN);
+ devpriv->old_chan_reg=-1; // invalidate chain/gain memory
+ devpriv->old_gain_reg=-1;
+
+ switch (this_board->board_type) {
+ case boardPCL812PG:
+ case boardPCL812:
+ case boardACL8112:
+ case boardACL8216:
outb(0, dev->iobase + PCL812_DA2_LO);
outb(0, dev->iobase + PCL812_DA2_HI);
+ case boardA821:
+ outb(0, dev->iobase + PCL812_DA1_LO);
+ outb(0, dev->iobase + PCL812_DA1_HI);
+ start_pacer(dev,-1,0,0); // stop 8254
outb(0, dev->iobase + PCL812_DO_HI);
outb(0, dev->iobase + PCL812_DO_LO);
- outb(0, dev->iobase + PCL812_MODE);
+ outb(devpriv->mode_reg_int|0, dev->iobase + PCL812_MODE);
outb(0, dev->iobase + PCL812_CLRINT);
+ break;
+ case boardPCL813B:
+ case boardPCL813:
+ case boardISO813:
+ case boardACL8113:
+ udelay(5);
+ break;
}
- outb(0, dev->iobase + PCL812_GAIN);
- outb(0, dev->iobase + PCL812_MUX);
udelay(5);
- if (this_board->is_813b){
-#ifdef PCL813_MICROSECS
- udelay(5);
-#else
- udelay(5000);
+#ifdef PCL812_EXTDEBUG
+ rt_printk("pcl812 EDBG: END: pcl812_reset(...)\n");
#endif
- }
}
/*
==============================================================================
-
- Initialization
-
*/
static int pcl812_attach(comedi_device * dev, comedi_devconfig * it)
{
-
- int ret;
+ int ret,subdev;
int iobase;
int irq;
-#ifdef USE_DMA
int dma;
unsigned long pages;
-#endif
comedi_subdevice *s;
- int num_of_subdevs, subdevs[5];
- /* claim our I/O space */
iobase = it->options[0];
printk("comedi%d: pcl812: board=%s, ioport=0x%03x", dev->minor,
this_board->name, iobase);
+
if (check_region(iobase, this_board->io_range) < 0) {
printk("I/O port conflict\n");
return -EIO;
request_region(iobase, this_board->io_range, "pcl812");
dev->iobase = iobase;
- /* there should be a sanity check here */
-
- if ((ret = alloc_private(dev, sizeof(pcl812_private))) < 0)
+ if ((ret = alloc_private(dev, sizeof(pcl812_private))) < 0) {
+ free_resources(dev);
return ret; /* Can't alloc mem */
+ }
- /* set up some name stuff */
dev->board_name = this_board->name;
- /* grab our IRQ */
irq = 0;
if (this_board->IRQbits != 0) { /* board support IRQ */
irq = it->options[1];
}
dev->irq = irq;
- if (irq) {
- devpriv->irq_free = 1;
- } /* 1=we have allocated irq */
- else {
- devpriv->irq_free = 0;
- }
- devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
- devpriv->int812_mode = 0; /* mode of irq */
-#ifdef USE_DMA
- /* grab our DMA */
dma = 0;
devpriv->dma = dma;
- if (!devpriv->irq_free)
+ if (!dev->irq)
goto no_dma; /* if we haven't IRQ, we can't use DMA */
- if (boardtypes[board].DMAbits != 0) { /* board support DMA */
+ if (this_board->DMAbits != 0) { /* board support DMA */
dma = it->options[2];
- if (((1 << dma) & boardtypes[board].DMAbits) == 0) {
+ if (((1 << dma) & this_board->DMAbits) == 0) {
printk(", DMA is out of allowed range, FAIL!\n");
return -EINVAL; /* Bad DMA */
}
}
devpriv->dma = dma;
printk(", dma=%d", dma);
- pages = 1; /* we need 8KB */
+ pages = 1; /* we want 8KB */
devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[0]) {
printk(", unable to allocate DMA buffer, FAIL!\n");
/* maybe experiment with try_to_free_pages() will help .... */
+ free_resources(dev);
return -EBUSY; /* no buffer :-( */
}
devpriv->dmapages[0] = pages;
devpriv->hwdmaptr[0] = virt_to_bus((void *) devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = PAGE_SIZE * 2;
+ devpriv->hwdmasize[0] = PAGE_SIZE * (1<<pages);
devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[1]) {
printk(", unable to allocate DMA buffer, FAIL!\n");
+ free_resources(dev);
return -EBUSY;
}
devpriv->dmapages[1] = pages;
devpriv->hwdmaptr[1] = virt_to_bus((void *) devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = PAGE_SIZE * 2;
+ devpriv->hwdmasize[1] = PAGE_SIZE * (1<<pages);
}
no_dma:
-#endif
- num_of_subdevs = 0;
+ dev->n_subdevices=0;
- /*if (!((board==boardPCL812PG)&&(it->options[3]==1))) { */
- subdevs[num_of_subdevs++] = COMEDI_SUBD_AI;
- /* } */
- if (this_board->n_aochan > 0)
- subdevs[num_of_subdevs++] = COMEDI_SUBD_AO;
- if (this_board->n_dichan > 0)
- subdevs[num_of_subdevs++] = COMEDI_SUBD_DI;
- if (this_board->n_dochan > 0)
- subdevs[num_of_subdevs++] = COMEDI_SUBD_DO;
+ if (this_board->n_aichan > 0) dev->n_subdevices++;
+ if (this_board->n_aochan > 0) dev->n_subdevices++;
+ if (this_board->n_dichan > 0) dev->n_subdevices++;
+ if (this_board->n_dochan > 0) dev->n_subdevices++;
- dev->n_subdevices = 4;
- if ((ret = alloc_subdevices(dev)) < 0)
+ if ((ret = alloc_subdevices(dev)) < 0) {
+ free_resources(dev);
return ret;
+ }
+
+ subdev=0;
/* analog input */
- s = dev->subdevices + 0;
- if (this_board->n_aichan == 0) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
+ if (this_board->n_aichan>0) {
+ s = dev->subdevices + subdev;
+ dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE;
- s->n_chan = this_board->n_aichan;
- s->maxdata = 0xfff;
- s->len_chanlist = AI_LEN_CHANLIST;
- s->range_table = this_board->ai_range_type;
- s->subdev_flags |= SDF_GROUND;
- s->insn_read = pcl812_ai_insn_read;
- if(this_board->is_812pg){
- if (it->options[3] == 1)
+ switch (this_board->board_type) {
+ case boardA821:
+ if (it->options[2] == 1) {
+ s->n_chan = this_board->n_aichan_diff;
+ s->subdev_flags |= SDF_DIFF;
+ devpriv->use_diff=1;
+ } else {
+ s->n_chan = this_board->n_aichan;
+ s->subdev_flags |= SDF_GROUND;
+ }
+ break;
+ case boardACL8112:
+ case boardACL8216:
+ if (it->options[4] == 1) {
+ s->n_chan = this_board->n_aichan_diff;
+ s->subdev_flags |= SDF_DIFF;
+ devpriv->use_diff=1;
+ } else {
+ s->n_chan = this_board->n_aichan;
+ s->subdev_flags |= SDF_GROUND;
+ }
+ break;
+ default:
+ s->n_chan = this_board->n_aichan;
+ s->subdev_flags |= SDF_GROUND;
+ break;
+ }
+ s->maxdata = this_board->ai_maxdata;
+ s->len_chanlist = MAX_CHANLIST_LEN;
+ s->range_table = this_board->rangelist_ai;
+ if (this_board->board_type==boardACL8216) {
+ s->insn_read = acl8216_ai_insn_read;
+ } else {
+ s->insn_read = pcl812_ai_insn_read;
+ }
+ devpriv->use_MPC = this_board->haveMPC508;
+ s->cancel = pcl812_ai_cancel;
+ if (dev->irq) {
+ s->do_cmdtest = pcl812_ai_cmdtest;
+ s->do_cmd = pcl812_ai_cmd;
+ s->poll = pcl812_ai_poll;
+ }
+ switch (this_board->board_type) {
+ case boardPCL812PG:
+ if (it->options[4] == 1)
s->range_table = &range_pcl812pg2_ai;
-#ifdef CONFIG_COMEDI_TRIG
- if (dev->irq) {
- if (it->options[2] != 1) {
- s->trig[1] = pcl812_ai_mode1;
- } else {
- s->trig[3] = pcl812_ai_mode3_int;
- }
+ break;
+ case boardPCL812:
+ switch (it->options[4]) {
+ case 0: s->range_table = &range_bipolar10; break;
+ case 1: s->range_table = &range_bipolar5; break;
+ case 2: s->range_table = &range_bipolar2_5; break;
+ case 3: s->range_table = &range812_bipolar1_25; break;
+ case 4: s->range_table = &range812_bipolar0_625; break;
+ case 5: s->range_table = &range812_bipolar0_3125; break;
+ default:
+ s->range_table = &range_bipolar10; break;
+ printk(", incorrect range number %d, changing to 0 (+/-10V)", it->options[4]);
+ break;
}
-#endif
- }else{
+ break;
+ break;
+ case boardPCL813B:
if (it->options[1] == 1)
s->range_table = &range_pcl813b2_ai;
+ break;
+ case boardISO813:
+ switch (it->options[1]) {
+ case 0: s->range_table = &range_iso813_1_ai; break;
+ case 1: s->range_table = &range_iso813_1_2_ai; break;
+ case 2: s->range_table = &range_iso813_2_ai; devpriv->range_correction=1; break;
+ case 3: s->range_table = &range_iso813_2_2_ai; devpriv->range_correction=1; break;
+ default:
+ s->range_table = &range_iso813_1_ai; break;
+ printk(", incorrect range number %d, changing to 0 ", it->options[1]);
+ break;
+ }
+ break;
+ case boardACL8113:
+ switch (it->options[1]) {
+ case 0: s->range_table = &range_acl8113_1_ai; break;
+ case 1: s->range_table = &range_acl8113_1_2_ai; break;
+ case 2: s->range_table = &range_acl8113_2_ai; devpriv->range_correction=1; break;
+ case 3: s->range_table = &range_acl8113_2_2_ai; devpriv->range_correction=1; break;
+ default:
+ s->range_table = &range_acl8113_1_ai; break;
+ printk(", incorrect range number %d, changing to 0 ", it->options[1]);
+ break;
+ }
+ break;
}
+ subdev++;
}
/* analog output */
- s = dev->subdevices + 1;
- if (this_board->n_aochan == 0) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
+ if (this_board->n_aochan>0) {
+ s = dev->subdevices + subdev;
s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE;
+ s->subdev_flags = SDF_WRITEABLE|SDF_GROUND;
s->n_chan = this_board->n_aochan;
s->maxdata = 0xfff;
s->len_chanlist = 1;
- s->range_table = this_board->ao_range_type;
- if(this_board->is_812pg){
- s->subdev_flags |= SDF_GROUND;
- s->insn_read = pcl812_ao_insn_read;
- s->insn_write = pcl812_ao_insn_write;
- if (it->options[4] == 1)
- s->range_table = &range_unipolar5;
- if (it->options[4] == 2)
+ s->range_table = this_board->rangelist_ao;
+ s->insn_read = pcl812_ao_insn_read;
+ s->insn_write = pcl812_ao_insn_write;
+ switch (this_board->board_type) {
+ case boardA821:
+ if (it->options[3] == 1)
+ s->range_table = &range_unipolar10;
+ break;
+ case boardPCL812:
+ case boardACL8112:
+ case boardPCL812PG:
+ case boardACL8216:
+ if (it->options[5] == 1)
+ s->range_table = &range_unipolar10;
+ if (it->options[5] == 2)
s->range_table = &range_unknown;
+ break;
}
+ subdev++;
}
/* digital input */
- s = dev->subdevices + 2;
- if (this_board->n_dichan == 0) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
+ if (this_board->n_dichan>0) {
+ s = dev->subdevices + subdev;
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = this_board->n_dichan;
s->len_chanlist = this_board->n_dichan;
s->range_table = &range_digital;
s->insn_bits = pcl812_di_insn_bits;
+ subdev++;
}
/* digital output */
- s = dev->subdevices + 3;
- if (this_board->n_dochan == 0) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
+ if (this_board->n_dochan>0) {
+ s = dev->subdevices + subdev;
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITEABLE;
s->n_chan = this_board->n_dochan;
s->len_chanlist = this_board->n_dochan;
s->range_table = &range_digital;
s->insn_bits = pcl812_do_insn_bits;
+ subdev++;
}
- pcl812_reset(dev);
- if(this_board->is_812pg){
- devpriv->max_812_ai_mode0_samples = 32;
+ switch (this_board->board_type) {
+ case boardACL8216:
+ devpriv->ai_is16b=1;
+ case boardPCL812PG:
+ case boardPCL812:
+ case boardACL8112:
devpriv->max_812_ai_mode0_rangewait = 1;
- devpriv->max_812_ai_mode0_chanset = 1;
- devpriv->max_812_ai_mode0_convstart = 5;
- }
- if(this_board->is_813b){
- if (it->options[2] < 2) {
- devpriv->max_812_ai_mode0_samples = 1;
- } else {
- devpriv->max_812_ai_mode0_samples = it->options[2];
- }
-#ifdef PCL813_MICROSECS
- devpriv->max_812_ai_mode0_rangewait = 1; /* maybe there must by greatest timeout */
- devpriv->max_812_ai_mode0_chanset = 5;
- devpriv->max_812_ai_mode0_convstart = 20;
-#else
- devpriv->max_812_ai_mode0_rangewaint = 1;
- devpriv->max_812_ai_mode0_chanset = 5000;
- devpriv->max_812_ai_mode0_convstart = 20000;
-#endif
+ if (it->options[3] > 0) devpriv->use_ext_trg=1; // we use external trigger
+ case boardA821:
+ devpriv->max_812_ai_mode0_rangewait = 1;
+ devpriv->mode_reg_int=(irq<<4) & 0xf0;
+ break;
+ case boardPCL813B:
+ case boardPCL813:
+ case boardISO813:
+ case boardACL8113:
+ devpriv->max_812_ai_mode0_rangewait = 5; /* maybe there must by greatest timeout */
+ break;
}
+
printk("\n");
+ devpriv->valid=1;
+
+ pcl812_reset(dev);
+
return 0;
}
/*
==============================================================================
- Removes device
*/
static int pcl812_detach(comedi_device * dev)
{
-#ifdef MD_DEBUG
- printk("comedi%d: pcl812: remove\n", dev->minor);
+#ifdef PCL812_EXTDEBUG
+ rt_printk("comedi%d: pcl812: remove\n", dev->minor);
#endif
free_resources(dev);
return 0;
}
-
-#if 0
-/* @@Kluvi: magic crystaline sphere error correction, I hope
- that work identicaly under C and TP :-) */
-static void Zisti_Div8254(long celk, long *d1, long *d2)
-{
- long minch, chyba, mini, i;
-
- minch = 32000;
- mini = 1;
- if (celk <= (65536 * 2)) {
- i = 2;
- } else {
- i = celk / 65536;
- }
- do {
- *d1 = i;
- *d2 = celk / *d1;
- if (*d2 < 65536) {
- chyba = celk - *d1 * *d2;
- if (chyba < 0) {
- chyba = -chyba;
- }
- if (chyba < minch) {
- minch = chyba;
- mini = i;
- if (chyba == 0)
- break;
- }
- }
- i++;
- } while ((i < 65536) && (*d2 > 2) && (*d2 > *d1));
- i = mini;
- *d1 = i;
- *d2 = celk / *d1;
-}
-
-static int pcl812_timer(double freq, unsigned int *trigvar, double *actual_freq)
-{
- long divisor1, divisor2, divid;
- double Oscilator = 2e6;
-
- if (freq < 0.0004) {
- freq = 0.0004;
- }
- if (freq > 30000) {
- freq = 30000;
- }
- divid = rint(Oscilator / freq);
- Zisti_Div8254(divid, &divisor1, &divisor2);
- divid = rint(Oscilator / freq + 0.5 * (divid - divisor1 * divisor2));
- Zisti_Div8254(divid, &divisor1, &divisor2);
- *actual_freq = Oscilator / (divisor1 * divisor2);
-
- *trigvar = (divisor1 << 16) | divisor2;
- return 0;
-}
-
-#endif
-
-