📄 pcl818.c
字号:
if (mode==1) { devpriv->int818_mode=INT_TYPE_AI1_DMA; outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ } else { devpriv->int818_mode=INT_TYPE_AI3_DMA; outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ };}/* ============================================================================== ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards*/static void pcl818_ai_mode13dma_rtc(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { unsigned int flags; sampl_t *pole; set_dma_mode(devpriv->dma, DMA_MODE_READ|DMA_AUTOINIT); flags=claim_dma_lock(); clear_dma_ff(devpriv->dma); set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); set_dma_count(devpriv->dma, devpriv->hwdmasize[0]); release_dma_lock(flags); enable_dma(devpriv->dma); devpriv->last_top_dma=0; //devpriv->hwdmasize[0]; pole=(sampl_t *)devpriv->dmabuf[0]; devpriv->dmasamplsize=devpriv->hwdmasize[0]/2; pole[devpriv->dmasamplsize-1]=MAGIC_DMA_WORD; devpriv->rtc_freq=rtc_setfreq_irq(2048); devpriv->rtc_irq_timer.expires=jiffies + HZ/devpriv->rtc_freq + 2*HZ/100; devpriv->rtc_irq_timer.data=(unsigned long)dev; devpriv->rtc_irq_timer.function=rtc_dropped_irq; add_timer(&devpriv->rtc_irq_timer); if (mode==1) { devpriv->int818_mode=INT_TYPE_AI1_DMA_RTC; outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */ } else { devpriv->int818_mode=INT_TYPE_AI3_DMA_RTC; outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */ };}/* ============================================================================== ANALOG INPUT MODE 1 or 3, 818 cards*/static int pcl818_ai_mode13(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { int divisor1, divisor2; if ((!dev->irq)&&(!devpriv->dma_rtc)) { comedi_error(dev,"IRQ not defined!"); return -EINVAL; } if (devpriv->irq_blocked) return -EBUSY; start_pacer(dev, -1, 0, 0); // stop pacer if (!check_and_setup_channel_list(dev, s, it)) return -EINVAL; comedi_udelay(1); devpriv->int13_act_scan=it->n; devpriv->int13_act_chan=0; devpriv->irq_blocked=1; devpriv->irq_was_now_closed=0; devpriv->neverending_ai=0; devpriv->act_chanlist_pos=0; devpriv->buf_ptr=0; if ((it->n==0)||(it->n==-1)) devpriv->neverending_ai=1; //well, user want neverending if (mode==1) { if (it->trigvar<devpriv->ns_min) it->trigvar=devpriv->ns_min; i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&it->trigvar,TRIG_ROUND_NEAREST); if (divisor1==1) { /* PCL718/818 crash if any divisor is set to 1 */ divisor1=2; divisor2/=2; } if (divisor2==1) { divisor2=2; divisor1/=2; } } outb(0 , dev->iobase + PCL818_CNTENABLE); /* enable pacer */ switch (devpriv->dma>0) { case 1: // DMA case 3: if (devpriv->dma_rtc==0) { pcl818_ai_mode13dma_int(mode, dev, s, it); } else { pcl818_ai_mode13dma_rtc(mode, dev, s, it); } break; case 0: // IRQ // rt_printk("IRQ\n"); if (mode==1) { devpriv->int818_mode=INT_TYPE_AI1_INT; outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */ } else { devpriv->int818_mode=INT_TYPE_AI3_INT; outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */ }; break; case -1: // FIFO outb(1, dev->iobase + PCL818_FI_ENABLE); // enable FIFO if (mode==1) { devpriv->int818_mode=INT_TYPE_AI1_FIFO; outb(0x03, dev->iobase + PCL818_CONTROL); /* Pacer */ } else { devpriv->int818_mode=INT_TYPE_AI3_FIFO; outb(0x02, dev->iobase + PCL818_CONTROL); }; /* Ext trig */ break; } start_pacer(dev, mode, divisor1, divisor2); switch(devpriv->int818_mode) { case INT_TYPE_AI1_DMA_RTC: case INT_TYPE_AI3_DMA_RTC: set_rtc_irq_bit(1); /* start RTC */ break; } return 0;}/* ============================================================================== ANALOG INPUT MODE 1, 818 cards*/static int pcl818_ai_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { return pcl818_ai_mode13(1, dev, s, it);}/* ============================================================================== ANALOG INPUT MODE 3, 818 cards*/static int pcl818_ai_mode3(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { return pcl818_ai_mode13(3, dev, s, it);}/*============================================================================== ANALOG OUTPUT MODE 1 or 3, 818 cards*/#ifdef PCL818_MODE13_AOstatic int pcl818_ao_mode13(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { int divisor1, divisor2; if (!dev->irq) { comedi_error(dev,"IRQ not defined!"); return -EINVAL; } if (devpriv->irq_blocked) return -EBUSY; start_pacer(dev, -1, 0, 0); // stop pacer devpriv->int13_act_scan=it->n; devpriv->int13_act_chan=0; devpriv->irq_blocked=1; devpriv->irq_was_now_closed=0; devpriv->neverending_ai=0; devpriv->act_chanlist_pos=0; devpriv->buf_ptr=0; if (mode==1) { i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&it->trigvar,TRIG_ROUND_NEAREST); if (divisor1==1) { /* PCL818 crash if any divisor is set to 1 */ divisor1=2; divisor2/=2; } if (divisor2==1) { divisor2=2; divisor1/=2; } } outb(0 , dev->iobase + PCL818_CNTENABLE); /* enable pacer */ if (mode==1) { devpriv->int818_mode=INT_TYPE_AO1_INT; outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */ } else { devpriv->int818_mode=INT_TYPE_AO3_INT; outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */ }; start_pacer(dev, mode, divisor1, divisor2); return 0;}/* ============================================================================== ANALOG OUTPUT MODE 1, 818 cards*/static int pcl818_ao_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { return pcl818_ao_mode13(1, dev, s, it);}/* ============================================================================== ANALOG OUTPUT MODE 3, 818 cards*/static int pcl818_ao_mode3(comedi_device * dev, comedi_subdevice * s, comedi_trig * it) { return pcl818_ao_mode13(3, dev, s, it);}#endif#endif/*============================================================================== Start/stop pacer onboard pacer*/#ifdef unusedstatic void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) { outb(0xb4, dev->iobase + PCL818_CTRCTL); outb(0x74, dev->iobase + PCL818_CTRCTL); outb(0x30, dev->iobase + PCL818_CTRCTL); comedi_udelay(1); if (mode==1) { outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); }}/*============================================================================== Check if channel list from user is builded correctly If it's ok, then program scan/gain logic*/static int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, comedi_trig * it){ unsigned int chansegment[16]; unsigned int i, nowmustbechan, seglen, segpos; /* correct channel and range number check itself comedi/range.c */ if (it->n_chan<1) { comedi_error(dev,"range/channel list is empty!"); return 0; } if (it->n_chan > 1) { // first channel is everytime ok chansegment[0]=it->chanlist[0]; // build part of chanlist for (i=1, seglen=1; i<it->n_chan; i++, seglen++) { // rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); // we detect loop, this must by finish if (it->chanlist[0]==it->chanlist[i]) break; nowmustbechan=(CR_CHAN(chansegment[i-1])+1) % s->n_chan; // channel list isn't continous :-( if (nowmustbechan!=CR_CHAN(it->chanlist[i])) { rt_printk("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", dev->minor,i,CR_CHAN(it->chanlist[i]), nowmustbechan,CR_CHAN(it->chanlist[0]) ); return 0; } // well, this is next correct channel in list chansegment[i]=it->chanlist[i]; } // check whole chanlist for (i=0, segpos=0; i<it->n_chan; i++) { //rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); if (it->chanlist[i]!=chansegment[i%seglen]) { rt_printk("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", dev->minor,i,CR_CHAN(chansegment[i]), CR_RANGE(chansegment[i]), CR_AREF(chansegment[i]), CR_CHAN(it->chanlist[i%seglen]), CR_RANGE(it->chanlist[i%seglen]), CR_AREF(chansegment[i%seglen])); return 0; // chan/gain list is strange } } } else { seglen=1; } devpriv->act_chanlist_len=seglen; devpriv->act_chanlist_pos=0; for (i=0; i<seglen; i++) { // store range list to card devpriv->act_chanlist[i]=CR_CHAN(it->chanlist[i]); outb(muxonechan[CR_CHAN(it->chanlist[i])], dev->iobase+PCL818_MUX); /* select channel */ outb(CR_RANGE(it->chanlist[i]), dev->iobase+PCL818_RANGE); /* select gain */ } comedi_udelay(1); /* select channel interval to sca n*/ outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen-1] << 4), dev->iobase+PCL818_MUX); // printk(" MUX %x\n",devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen-1] << 4)); // we can serve this with MUX logic return 1;}#endif/* ============================================================================== Check if board is switched to SE (1) or DIFF(0) mode*/static int check_single_ended(unsigned int port){ if (inb(port+PCL818_STATUS)&0x20) { return 1; } else { return 0; }}/* ============================================================================== cancel any mode 1-4 AI*/static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s) { if (devpriv->irq_blocked>0) { // rt_printk("pcl818_ai_cancel()\n"); switch (devpriv->int818_mode) { case INT_TYPE_AI1_DMA_RTC: case INT_TYPE_AI3_DMA_RTC: set_rtc_irq_bit(0); // stop RTC del_timer(&devpriv->rtc_irq_timer); case INT_TYPE_AI1_DMA: case INT_TYPE_AI3_DMA: disable_dma(devpriv->dma); case INT_TYPE_AI1_INT: case INT_TYPE_AI3_INT: case INT_TYPE_AI1_FIFO: case INT_TYPE_AI3_FIFO:#ifdef PCL818_MODE13_AO case INT_TYPE_AO1_INT: case INT_TYPE_AO3_INT:#endif outb(inb(dev->iobase+PCL818_CONTROL)& 0x73, dev->iobase+PCL818_CONTROL); /* Stop A/D */ comedi_udelay(1); outb(0, dev->iobase+PCL818_CONTROL); /* Stop A/D */ outb(0xb4, dev->iobase + PCL818_CTRCTL);/* Stop pacer */ outb(0x74, dev->iobase + PCL818_CTRCTL); outb(0, dev->iobase+PCL818_AD_LO); inb(dev->iobase+PCL818_AD_LO); inb(dev->iobase+PCL818_AD_HI); outb(0, dev->iobase+PCL818_CLRINT); /* clear INT request */ outb(0, dev->iobase+PCL818_CONTROL); /* Stop A/D */ if (devpriv->usefifo) { // FIFO shutdown outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } devpriv->irq_blocked=0; devpriv->irq_was_now_closed=devpriv->int818_mode; devpriv->int818_mode=0; devpriv->last_int_sub=s; break; } } //rt_printk("pcl818_ai_cancel() end\n"); return 0;}/* ============================================================================== chech for PCL818*/static int pcl818_check(int iobase) { outb(0x00, iobase + PCL818_MUX); comedi_udelay(1); if (inb(iobase + PCL818_MUX)!=0x00) return 1; //there isn't card outb(0x55, iobase + PCL818_MUX); comedi_udelay(1); if (inb(iobase + PCL818_MUX)!=0x55) return 1; //there isn't card outb(0x00, iobase + PCL818_MUX); comedi_udelay(1); outb(0x18, iobase + PCL818_CONTROL); comedi_udelay(1); if (inb(iobase + PCL818_CONTROL)!=0x18) return 1; //there isn't card return 0; // ok, card exist}/* ============================================================================== reset whole PCL-818 cards*/static void pcl818_reset(comedi_device * dev) { if (devpriv->usefifo) { // FIFO shutdown outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -