📄 pcl812.c
字号:
for(i=0;i<insn->n;i++){ outb((data[i] & 0xff), dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO)); outb((data[i] >> 8) & 0x0f, dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI)); devpriv->ao_readback[chan]=data[i]; } return i;}/* ==============================================================================*/static int pcl812_ao_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int chan = CR_CHAN(insn->chanspec); int i; for(i=0;i<insn->n;i++){ data[i] = devpriv->ao_readback[chan]; } return i;}/* ==============================================================================*/static int pcl812_di_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; data[1] = inb(dev->iobase + PCL812_DI_LO); data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; return 2;}/* ==============================================================================*/static int pcl812_do_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; if(data[0]){ s->state &= ~data[0]; s->state |= data[0]&data[1]; outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); outb((s->state >> 8), dev->iobase + PCL812_DO_HI); } data[1]=s->state; return 2;}#ifdef PCL812_EXTDEBUG/* ==============================================================================*/static 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;#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 */ 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++; 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++; 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) {#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 { 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 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>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++; } } 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;}/* ==============================================================================*/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 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); } 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->prealloc_bufsz; devpriv->ai_data=s->async->prealloc_buf; 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 } 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;}/* ==============================================================================*/static void interrupt_pcl812_ai_int(int irq, void *d, struct pt_regs *regs){ char err=1; unsigned int mask, timeout; comedi_device *dev = d; comedi_subdevice *s = dev->subdevices + 0; s->async->events = 0; 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; } comedi_udelay(1); } } else { mask=0x0fff; while (timeout--) { if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { err=0; break; } comedi_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; } comedi_buf_put( s->async, ((inb(dev->iobase + PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO)) & mask); outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ if (s->async->cur_chan == 0 ) { /* one scan done */ devpriv->ai_act_scan++; 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; } } comedi_event(dev,s,s->async->events);}/* ==============================================================================*/static void transfer_from_dma_buf(comedi_device *dev,comedi_subdevice *s, sampl_t *ptr, unsigned int bufptr, unsigned int len){ unsigned int i; s->async->events = 0; for (i=len; i; i--) { comedi_buf_put( s->async, ptr[bufptr++] ); // get one sample if(s->async->cur_chan == 0){ devpriv->ai_act_scan++; 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; } } } 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}/* ==============================================================================*/static void interrupt_pcl812(int irq, void *d, struct pt_regs *regs){ comedi_device *dev = d;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -