📄 pcl812.c
字号:
/* * comedi/drivers/pcl812.c * * Author: Michal Dobes <dobes@tesnet.cz> * * hardware driver for Advantech cards * 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 *//*Driver: pcl812.oDescription: Advantech PCL-812/PG, PCL-813/B, ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG, ICP DAS ISO-813Author: Michal Dobes <dobes@tesnet.cz>Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg), PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg), ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216), [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl), A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl), A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg)Status: works (I hope. My board fire up under my hands and I cann't test all features.)This driver supports insn and cmd interfaces. Some boards support only insnbecouse their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813).Data transfer over DMA is supported only when you measure only onechannel, this is too hardware limitation of these boards.See the head of the source file pcl812.c for configuration options.*//* * * Options for PCL-812: * [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 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 * [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 * * 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 <linux/delay.h>#include <linux/ioport.h>#include <asm/dma.h>#include "8253.h"#undef PCL812_EXTDEBUG /* if this is defined then a lot of messages is printed */// 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 PCLx1x_IORANGE 16#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 PCL812_DRDY 0x10 /* =0 data ready */#define ACL8216_STATUS 8 /* 5. bit signalize data ready */#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(2.5), BIP_RANGE(1.25), BIP_RANGE(0.625), BIP_RANGE(0.3125),}};static comedi_lrange range_pcl812pg2_ai = { 5, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.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), BIP_RANGE(1.25), BIP_RANGE(0.625),}};static comedi_lrange range_pcl813b2_ai = { 4, { UNI_RANGE(10), UNI_RANGE(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);typedef struct { 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[] ={ {"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))#define this_board ((boardtype *)dev->board_ptr)static comedi_driver driver_pcl812={ driver_name: "pcl812", module: THIS_MODULE, attach: pcl812_attach, detach: pcl812_detach, board_name: boardtypes, num_names: n_boardtypes, offset: sizeof(boardtype),};COMEDI_INITCLEANUP(driver_pcl812);typedef struct { 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)/* ==============================================================================*/static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);static void setup_range_channel(comedi_device * dev, comedi_subdevice * s, unsigned int rangechan, char wait);static 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(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 */ comedi_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; comedi_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(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 */ comedi_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; comedi_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;}/* ==============================================================================*/static int pcl812_ao_insn_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int chan = CR_CHAN(insn->chanspec); int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -