📄 pcl816.c
字号:
if(!dev->attached) { comedi_error(dev, "premature interrupt"); return; } switch (devpriv->int816_mode) { case INT_TYPE_AI1_DMA: case INT_TYPE_AI3_DMA: interrupt_pcl816_ai_mode13_dma (irq, d, regs); return; case INT_TYPE_AI1_INT: case INT_TYPE_AI3_INT: interrupt_pcl816_ai_mode13_int (irq, d, regs); return; } outb (0, dev->iobase + PCL816_CLRINT); /* clear INT request */ if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) | (!devpriv->int816_mode)) { if (devpriv->irq_was_now_closed) { devpriv->irq_was_now_closed = 0; // comedi_error(dev,"last IRQ.."); return; } comedi_error (dev, "bad IRQ!"); return; } comedi_error (dev, "IRQ from unknow source!");}/*============================================================================== COMMAND MODE*/static void pcl816_cmdtest_out(int e,comedi_cmd *cmd) { rt_printk("pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n",e,cmd->start_src,cmd->scan_begin_src,cmd->convert_src); rt_printk("pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n",e,cmd->start_arg,cmd->scan_begin_arg,cmd->convert_arg); rt_printk("pcl816 e=%d stopsrc=%x scanend=%x\n",e,cmd->stop_src,cmd->scan_end_src); rt_printk("pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",e,cmd->stop_arg,cmd->scan_end_arg,cmd->chanlist_len);}/* ==============================================================================*/static int pcl816_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){ int err=0; int tmp,divisor1,divisor2;DEBUG( rt_printk("pcl816 pcl812_ai_cmdtest\n"); pcl816_cmdtest_out(-1, cmd);); /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; cmd->start_src &= TRIG_NOW; if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_FOLLOW; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; if(!cmd->convert_src & (TRIG_EXT | TRIG_TIMER)) err++; tmp=cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++; tmp=cmd->stop_src; cmd->stop_src &= TRIG_COUNT|TRIG_NONE; if(!cmd->stop_src || tmp!=cmd->stop_src)err++; if(err) { 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(cmd->convert_src!=TRIG_EXT && 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) { return 2; } /* 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(!cmd->chanlist_len){ cmd->chanlist_len=1; err++; } if(cmd->chanlist_len > this_board->n_aichan){ 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++; } } if(err) { 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) { return 4; } return 0;}static int pcl816_ai_cmd(comedi_device *dev,comedi_subdevice *s){ unsigned int divisor1, divisor2, dma_flags, bytes, dmairq; comedi_cmd *cmd=&s->async->cmd; if(cmd->start_src!=TRIG_NOW) return -EINVAL; if(cmd->scan_begin_src!=TRIG_FOLLOW) 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 (devpriv->irq_blocked) return -EBUSY; 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 (divisor1 == 1) { // PCL816 crash if any divisor is set to 1 divisor1 = 2; divisor2 /= 2; } if (divisor2 == 1) { divisor2 = 2; divisor1 /= 2; } } start_pacer(dev, -1, 0, 0); // stop pacer if (!check_and_setup_channel_list (dev, s, cmd->chanlist, cmd->chanlist_len)) return -EINVAL; comedi_udelay (1); devpriv->ai_act_scan=0; s->async->cur_chan=0; devpriv->irq_blocked = 1; devpriv->ai_poll_ptr=0; devpriv->irq_was_now_closed = 0; 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; } if ((cmd->flags & TRIG_WAKE_EOS)) { // don't we want wake up every scan? printk("pl816: You wankt WAKE_EOS but I dont want handle it"); // devpriv->ai_eos=1; //if (devpriv->ai_n_chan==1) // devpriv->dma=0; // DMA is useless for this situation } if (devpriv->dma) { bytes = devpriv->hwdmasize[0]; if (!devpriv->ai_neverending) { bytes = s->async->cmd.chanlist_len * s->async->cmd.chanlist_len * sizeof (sampl_t); // how many devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fill devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved devpriv->dma_runs_to_end--; if (devpriv->dma_runs_to_end >= 0) bytes = devpriv->hwdmasize[0]; } else devpriv->dma_runs_to_end = -1; 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, bytes); release_dma_lock (dma_flags); enable_dma (devpriv->dma); } start_pacer(dev, 1, divisor1, divisor2); dmairq = ((devpriv->dma & 0x3)<<4) | (dev->irq & 0x7); switch (cmd->convert_src) { case TRIG_TIMER: devpriv->int816_mode = INT_TYPE_AI1_DMA; outb (0x32, dev->iobase + PCL816_CONTROL); // Pacer+IRQ+DMA outb(dmairq, dev->iobase + PCL816_STATUS); // write irq and DMA to card break; default: devpriv->int816_mode = INT_TYPE_AI3_DMA; outb (0x34, dev->iobase + PCL816_CONTROL); // Ext trig+IRQ+DMA outb(dmairq, dev->iobase + PCL816_STATUS); // write irq to card break; } DPRINTK("pcl816 END: pcl812_ai_cmd()\n"); return 0;}static int pcl816_ai_poll(comedi_device *dev,comedi_subdevice *s){ unsigned long flags; unsigned int top1,top2,i; if (!devpriv->dma) return 0; // poll is valid only for DMA transfer comedi_spin_lock_irqsave(&dev->spinlock, flags); for (i=0; i<20; i++) { top1 = get_dma_residue(devpriv->dma); // where is now DMA top2 = get_dma_residue(devpriv->dma); if (top1 == top2) break; } if (top1 != top2) { comedi_spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } top1 = devpriv->hwdmasize [0] - 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, (sampl_t*)devpriv->dmabuf[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_write_count - s->async->buf_read_count;}/* ============================================================================== cancel any mode 1-4 AI*/static intpcl816_ai_cancel (comedi_device * dev, comedi_subdevice * s){// DEBUG(rt_printk("pcl816_ai_cancel()\n");) if (devpriv->irq_blocked > 0) { switch (devpriv->int816_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: outb (inb (dev->iobase + PCL816_CONTROL) & 0x73, dev->iobase + PCL816_CONTROL); /* Stop A/D */ comedi_udelay (1); outb (0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ outb (0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ outb (0x70, dev->iobase + PCL816_CTRCTL); outb (0, dev->iobase + PCL816_AD_LO); inb (dev->iobase + PCL816_AD_LO); inb (dev->iobase + PCL816_AD_HI); outb (0, dev->iobase + PCL816_CLRINT); /* clear INT request */ outb (0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ devpriv->irq_blocked = 0; devpriv->irq_was_now_closed = devpriv->int816_mode; devpriv->int816_mode = 0; devpriv->last_int_sub = s;// s->busy = 0; break; } } DEBUG(rt_printk("comedi: pcl816_ai_cancel() successful\n");) return 0;}/* ============================================================================== chech for PCL816*/static int pcl816_check (int iobase){ outb (0x00, iobase + PCL816_MUX); comedi_udelay (1); if (inb (iobase + PCL816_MUX) != 0x00) return 1; //there isn't card outb (0x55, iobase + PCL816_MUX); comedi_udelay (1); if (inb (iobase + PCL816_MUX) != 0x55) return 1; //there isn't card outb (0x00, iobase + PCL816_MUX); comedi_udelay (1); outb (0x18, iobase + PCL816_CONTROL); comedi_udelay (1); if (inb (iobase + PCL816_CONTROL) != 0x18) return 1; //there isn't card return 0; // ok, card exist}/* ============================================================================== reset whole PCL-816 cards*/static voidpcl816_reset (comedi_device * dev){// outb (0, dev->iobase + PCL818_DA_LO); // DAC=0V// outb (0, dev->iobase + PCL818_DA_HI);// comedi_udelay (1);// outb (0, dev->iobase + PCL818_DO_HI); // DO=$0000// outb (0, dev->iobase + PCL818_DO_LO);// comedi_udelay (1); outb (0, dev->iobase + PCL816_CONTROL); outb (0, dev->iobase + PCL816_MUX); outb (0, dev->iobase + PCL816_CLRINT); outb (0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ outb (0x70, dev->iobase + PCL816_CTRCTL); outb (0x30, dev->iobase + PCL816_CTRCTL); outb (0, dev->iobase + PCL816_RANGE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -