📄 dt282x.c
字号:
comedi_error(dev, "A/D error"); dt282x_ai_cancel(dev,s); s->async->events |= COMEDI_CB_ERROR; comedi_event(dev,s,s->async->events); return; } supcsr = inw(dev->iobase + DT2821_SUPCSR); /*printk("supcsr=%02x\n",supcsr);*/ if (supcsr & DT2821_DMAD) { if(devpriv->dma_dir==DMA_MODE_READ) dt282x_ai_dma_interrupt(dev); else dt282x_ao_dma_interrupt(dev); return; } if ((dacsr = inw(dev->iobase + DT2821_DACSR)) & DT2821_DAERR) {#if 0 static int warn = 5; if(--warn<=0){ disable_irq(dev->irq); printk("disabling irq\n"); }#endif comedi_error(dev, "D/A error"); dt282x_ao_cancel(dev,s_ao); s->async->events |= COMEDI_CB_ERROR; comedi_event(dev,s_ao,s->async->events); return; } if (adcsr & DT2821_ADDONE) { data = (sampl_t) inw(dev->iobase + DT2821_ADDAT); data&=(1<<boardtype.adbits)-1; if(devpriv->ad_2scomp){ data^=1<<(boardtype.adbits-1); } ret = comedi_buf_put( s->async, data ); if(ret==0){ s->async->events |= COMEDI_CB_OVERFLOW; } devpriv->nread--; if(!devpriv->nread){ s->async->events |= COMEDI_CB_EOA; }else{ if(supcsr&DT2821_SCDN) update_supcsr(DT2821_STRIG); } comedi_event(dev,s,s->async->events); return; }}static void dt282x_load_changain(comedi_device * dev, int n, unsigned int *chanlist){ unsigned int i; unsigned int chan, range; outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR); for (i = 0; i < n; i++) { chan = CR_CHAN(chanlist[i]); range = CR_RANGE(chanlist[i]); update_adcsr((range << 4) | (chan)); } outw(n - 1, dev->iobase + DT2821_CHANCSR);}/* * Performs a single A/D conversion. * - Put channel/gain into channel-gain list * - preload multiplexer * - trigger conversion and wait for it to finish */static int dt282x_ai_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int i; devpriv->adcsr = DT2821_ADCLK; update_adcsr(0); dt282x_load_changain(dev, 1, &insn->chanspec); update_supcsr(DT2821_PRLD); wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME; ); for(i=0;i<insn->n;i++){ update_supcsr(DT2821_STRIG); wait_for(ad_done(), comedi_error(dev, "timeout\n"); return -ETIME; ); data[i] = inw(dev->iobase + DT2821_ADDAT) & ((1<<boardtype.adbits)-1); if (devpriv->ad_2scomp) data[i] ^= (1 << (boardtype.adbits - 1)); } return i;}static int dt282x_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,comedi_cmd *cmd){ int err=0; int tmp; /* 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|TRIG_EXT; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; 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)return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ /* note that mutual compatiblity is not an issue here */ if(cmd->scan_begin_src!=TRIG_FOLLOW && cmd->scan_begin_src!=TRIG_EXT)err++; if(cmd->stop_src!=TRIG_COUNT && cmd->stop_src!=TRIG_NONE)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_src==TRIG_FOLLOW){ /* internal trigger */ if(cmd->scan_begin_arg!=0){ cmd->scan_begin_arg=0; err++; } }else{ /* external trigger */ /* should be level/edge, hi/lo specification here */ if(cmd->scan_begin_arg!=0){ cmd->scan_begin_arg=0; err++; } } if(cmd->convert_arg<4000){ /* XXX board dependent */ cmd->convert_arg=4000; err++; }#define SLOWEST_TIMER (250*(1<<15)*255) if(cmd->convert_arg>SLOWEST_TIMER){ cmd->convert_arg=SLOWEST_TIMER; err++; } if(cmd->scan_end_arg!=cmd->chanlist_len){ cmd->scan_end_arg=cmd->chanlist_len; err++; } if(cmd->stop_src==TRIG_COUNT){ /* any count is allowed */ }else{ /* TRIG_NONE */ if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } } if(err)return 3; /* step 4: fix up any arguments */ tmp=cmd->convert_arg; dt282x_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->convert_arg)err++; if(err)return 4; return 0;}static int dt282x_ai_cmd(comedi_device * dev, comedi_subdevice * s){ comedi_cmd *cmd=&s->async->cmd; int timer; timer=dt282x_ns_to_timer(&cmd->convert_arg,TRIG_ROUND_NEAREST); outw(timer, dev->iobase + DT2821_TMRCTR); if(cmd->scan_begin_src==TRIG_FOLLOW){ /* internal trigger */ devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0; }else{ /* external trigger */ devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1; } update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT); devpriv->adcsr = 0; devpriv->ntrig=cmd->stop_arg*cmd->scan_end_arg; devpriv->nread=devpriv->ntrig; devpriv->dma_dir=DMA_MODE_READ; devpriv->current_dma_chan=0; prep_ai_dma(dev,0,0); enable_dma(devpriv->dma[0].chan); if(devpriv->ntrig){ prep_ai_dma(dev,1,0); enable_dma(devpriv->dma[1].chan); devpriv->supcsr |= DT2821_DDMA; update_supcsr(0); } devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE; update_adcsr(0); dt282x_load_changain(dev,cmd->chanlist_len,cmd->chanlist); devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE; update_adcsr(0); update_supcsr(DT2821_PRLD); wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME; ); if(cmd->scan_begin_src==TRIG_FOLLOW){ update_supcsr(DT2821_STRIG); }else{ devpriv->supcsr |= DT2821_XTRIG; update_supcsr(0); } return 0;}static int dt282x_ai_cancel(comedi_device * dev, comedi_subdevice * s){ devpriv->adcsr=0; update_adcsr(0); devpriv->supcsr = 0; update_supcsr(DT2821_ADCINIT); return 0;}static int dt282x_ns_to_timer(int *nanosec,int round_mode){ int prescale,base,divider; for(prescale=0;prescale<16;prescale++){ if(prescale==1)continue; base=250*(1<<prescale); switch(round_mode){ case TRIG_ROUND_NEAREST: default: divider=(*nanosec+base/2)/base; break; case TRIG_ROUND_DOWN: divider=(*nanosec)/base; break; case TRIG_ROUND_UP: divider=(*nanosec+base-1)/base; break; } if(divider<256){ *nanosec=divider*base; return (prescale<<8)|(255-divider); } } base=250*(1<<15); divider=255; *nanosec=divider*base; return (15<<8)|(255-divider);}/* * Analog output routine. Selects single channel conversion, * selects correct channel, converts from 2's compliment to * offset binary if necessary, loads the data into the DAC * data register, and performs the conversion. */static int dt282x_ao_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ data[0] = devpriv->ao[CR_CHAN(insn->chanspec)]; return 1;}static int dt282x_ao_insn_write(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data){ sampl_t d; unsigned int chan; chan = CR_CHAN(insn->chanspec); d = data[0]; d &= (1<<boardtype.dabits)-1; devpriv->ao[chan] = d; devpriv->dacsr |= DT2821_SSEL; if (chan) { /* select channel */ devpriv->dacsr |= DT2821_YSEL; if (devpriv->da0_2scomp) d ^= (1<<(boardtype.dabits-1)); } else { devpriv->dacsr &= ~DT2821_YSEL; if (devpriv->da1_2scomp) d ^= (1<<(boardtype.dabits-1)); } update_dacsr(0); outw(d, dev->iobase + DT2821_DADAT); update_supcsr(DT2821_DACON); return 1;}static int dt282x_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){ int err=0; int tmp; /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; cmd->start_src &= TRIG_INT; if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_TIMER; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; cmd->convert_src &= TRIG_NOW; 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_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 */ /* note that mutual compatiblity is not an issue here */ if(cmd->stop_src!=TRIG_COUNT && cmd->stop_src!=TRIG_NONE)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 < 5000 /* XXX unknown */){ cmd->scan_begin_arg = 5000; err++; } if(cmd->convert_arg != 0){ cmd->convert_arg = 0; err++; } if(cmd->scan_end_arg > 2){ /* XXX chanlist stuff? */ cmd->scan_end_arg = 2; err++; } if(cmd->stop_src==TRIG_COUNT){ /* any count is allowed */ }else{ /* TRIG_NONE */ if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } } if(err)return 3; /* step 4: fix up any arguments */ tmp=cmd->scan_begin_arg; dt282x_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->scan_begin_arg)err++; if(err)return 4; return 0;}static int dt282x_ao_inttrig(comedi_device *dev,comedi_subdevice *s, unsigned int x){ int size; if(x!=0)return -EINVAL; size = comedi_buf_read_n_available(s->async); if(size>devpriv->dma_maxsize)size=devpriv->dma_maxsize; if( size == 0){ rt_printk("dt282x: AO underrun\n"); return -EPIPE; } comedi_buf_memcpy_from(s->async, 0, devpriv->dma[0].buf, size); comedi_buf_read_free(s->async, size); prep_ao_dma(dev,0,size); enable_dma(devpriv->dma[0].chan); size = comedi_buf_read_n_available(s->async); if(size>devpriv->dma_maxsize)size=devpriv->dma_maxsize; if( size == 0){ rt_printk("dt282x: AO underrun\n"); return -EPIPE; } comedi_buf_memcpy_from(s->async, 0, devpriv->dma[1].buf, size); comedi_buf_read_free(s->async, size); prep_ao_dma(dev,1,size); enable_dma(devpriv->dma[1].chan); update_supcsr(DT2821_STRIG); s->async->inttrig=NULL; return 1;}static int dt282x_ao_cmd(comedi_device *dev,comedi_subdevice *s){ int timer; comedi_cmd *cmd=&s->async->cmd; devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA; update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT); devpriv->ntrig=cmd->stop_arg*cmd->chanlist_len; devpriv->nread=devpriv->ntrig; devpriv->dma_dir=DMA_MODE_WRITE; devpriv->current_dma_chan=0; timer=dt282x_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST); outw(timer, dev->iobase + DT2821_TMRCTR); devpriv->dacsr = DT2821_SSEL| DT2821_DACLK | DT2821_IDARDY; update_dacsr(0); s->async->inttrig=dt282x_ao_inttrig; return 0;}static int dt282x_ao_cancel(comedi_device * dev, comedi_subdevice * s){ devpriv->dacsr=0; update_dacsr(0); devpriv->supcsr = 0; update_supcsr(DT2821_DACINIT); return 0;}static int dt282x_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]&data[1]); outw(s->state, dev->iobase + DT2821_DIODAT); } data[1] = inw(dev->iobase + DT2821_DIODAT); return 2;}static int dt282x_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int mask; mask=(CR_CHAN(insn->chanspec)<8)?0x00ff:0xff00; if(data[0])s->io_bits|=mask; else s->io_bits&=~mask; if(s->io_bits&0x00ff)devpriv->dacsr|=DT2821_LBOE; else devpriv->dacsr&=~DT2821_LBOE; if(s->io_bits&0xff00)devpriv->dacsr|=DT2821_HBOE; else devpriv->dacsr&=~DT2821_HBOE; outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); return 1;}static comedi_lrange *ai_range_table[]={ &range_dt282x_ai_lo_bipolar, &range_dt282x_ai_lo_unipolar, &range_dt282x_ai_5_bipolar, &range_dt282x_ai_5_unipolar };static comedi_lrange *ai_range_pgl_table[]={ &range_dt282x_ai_hi_bipolar, &range_dt282x_ai_hi_unipolar };static comedi_lrange *opt_ai_range_lkup(int ispgl,int x){ if(ispgl){ if(x<0 || x>=2)x=0; return ai_range_pgl_table[x]; }else{ if(x<0 || x>=4)x=0; return ai_range_table[x]; }}static comedi_lrange *ao_range_table[]={ &range_bipolar10, &range_unipolar10, &range_bipolar5, &range_unipolar5, &range_bipolar2_5 };static comedi_lrange *opt_ao_range_lkup(int x){ if(x<0 || x>=5)x=0; return ao_range_table[x];}enum{ opt_iobase=0, opt_irq, opt_dma1, opt_dma2, /* i/o base, irq, dma channels */ opt_diff, /* differential */ opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */ opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */};/* options: 0 i/o base 1 irq 2 dma1 3 dma2 4 0=single ended, 1=differential 5 ai 0=straight binary, 1=2's comp 6 ao0 0=straight binary, 1=2's comp 7 ao1 0=straight binary, 1=2's comp 8 ai 0=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -