📄 adl_pci9118.c
字号:
devpriv->ai_add_back=1; } if (cmd->convert_src==TRIG_TIMER) { devpriv->usedma=0; // use INT transfer if scanlist have only one channel } } if ((cmd->flags&TRIG_WAKE_EOS) && (devpriv->ai_n_scanlen&1) && (devpriv->ai_n_scanlen>1)) { if (cmd->scan_begin_src==TRIG_FOLLOW) { //vpriv->useeoshandle=1; // change DMA transfer block to fit EOS on every second call devpriv->usedma=0; // XXX maybe can be corrected to use 16 bit DMA } else { // well, we must insert one sample to end of EOS to meet 32 bit transfer devpriv->ai_add_back=1; devpriv->usedma=1; // 16 bit DMA transfer } } if ((!(cmd->flags&TRIG_WAKE_EOS)) && (devpriv->ai_n_scanlen&1)) { devpriv->usedma=1; // 16 bit DMA transfer } } else { // interrupt transfer don't need any correction devpriv->usedma=0; } if ((devpriv->usedma==2)&&(devpriv->ai_data_len&3)) // if output buffer inn't alligned to 32 bit then use 16 bit DMA devpriv->usedma=1; // we need software S&H signal? It add two samples before every scan as minimum if (devpriv->usessh&&devpriv->softsshdelay) { devpriv->ai_add_front=2; if ((devpriv->usedma==1)&&(devpriv->ai_add_back==1)) {// move it to front devpriv->ai_add_front++; devpriv->ai_add_back=0; } if (cmd->convert_arg<this_board->ai_ns_min) cmd->convert_arg=this_board->ai_ns_min; addchans=devpriv->softsshdelay/cmd->convert_arg; if (devpriv->softsshdelay%cmd->convert_arg) addchans++; if (addchans>(devpriv->ai_add_front-1)) { // uff, still short :-( devpriv->ai_add_front=addchans+1; if (devpriv->usedma==1) if ((devpriv->ai_add_front+devpriv->ai_n_chan+devpriv->ai_add_back)&1) devpriv->ai_add_front++; // round up to 32 bit if (devpriv->usedma==2) if (devpriv->ai_add_front&1) devpriv->ai_add_front++; // round up to 32 bit } } // well, we now know what must be all added devpriv->ai_n_realscanlen= // what we must take from card in real to have ai_n_scanlen on output? (devpriv->ai_add_front+devpriv->ai_n_chan+devpriv->ai_add_back)* (devpriv->ai_n_scanlen / devpriv->ai_n_chan); DPRINTK("2 usedma=%d realscan=%d af=%u n_chan=%d ab=%d n_scanlen=%d\n", devpriv->usedma, devpriv->ai_n_realscanlen, devpriv->ai_add_front, devpriv->ai_n_chan, devpriv->ai_add_back, devpriv->ai_n_scanlen); // check and setup channel list if (!check_channel_list(dev, s, devpriv->ai_n_chan, devpriv->ai_chanlist, devpriv->ai_add_front, devpriv->ai_add_back)) return -EINVAL; if (!setup_channel_list(dev, s, devpriv->ai_n_chan, devpriv->ai_chanlist, 0, devpriv->ai_add_front, devpriv->ai_add_back, devpriv->usedma, devpriv->useeoshandle)) return -EINVAL; // compute timers settings // simplest way, fr=4Mhz/(tim1*tim2), channel manipulation without timers effect if (((cmd->scan_begin_src==TRIG_FOLLOW)||(cmd->scan_begin_src==TRIG_EXT)||(cmd->scan_begin_src==TRIG_INT))&&(cmd->convert_src==TRIG_TIMER)) { // both timer is used for one time if (cmd->scan_begin_src==TRIG_EXT) { devpriv->ai_do=4; } else { devpriv->ai_do=1; } pci9118_calc_divisors(devpriv->ai_do, dev, s, &cmd->scan_begin_arg, &cmd->convert_arg, devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, &devpriv->ai_divisor2, devpriv->usessh, devpriv->ai_add_front); devpriv->ai_timer2=cmd->convert_arg; } if ((cmd->scan_begin_src==TRIG_TIMER)&&((cmd->convert_src==TRIG_TIMER)||(cmd->convert_src==TRIG_NOW))) { // double timed action if (!devpriv->usedma) { comedi_error(dev,"cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!"); return -EIO; } devpriv->ai_do=2; pci9118_calc_divisors(devpriv->ai_do, dev, s, &cmd->scan_begin_arg, &cmd->convert_arg, devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, &devpriv->ai_divisor2, devpriv->usessh, devpriv->ai_add_front); devpriv->ai_timer1=cmd->scan_begin_arg; devpriv->ai_timer2=cmd->convert_arg; } if ((cmd->scan_begin_src==TRIG_FOLLOW)&&(cmd->convert_src==TRIG_EXT)) { devpriv->ai_do=3; } start_pacer(dev, -1, 0, 0); // stop pacer devpriv->AdControlReg=0; // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA outl(devpriv->AdControlReg,dev->iobase+PCI9118_ADCNTRL); devpriv->AdFunctionReg=AdFunction_PDTrg|AdFunction_PETrg; // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop outl(devpriv->AdFunctionReg,dev->iobase+PCI9118_ADFUNC); comedi_udelay(1); outl(0,dev->iobase+PCI9118_DELFIFO); // flush FIFO inl(dev->iobase+PCI9118_ADSTAT); // flush A/D and INT status register inl(dev->iobase+PCI9118_INTSRC); devpriv->ai_act_scan=0; devpriv->ai_act_scanpos=0; devpriv->ai_act_dmapos=0; s->async->cur_chan=0; devpriv->ai_buf_ptr=0; if (devpriv->usedma) { ret=pci9118_ai_docmd_dma(dev, s); } else { ret=pci9118_ai_docmd_sampl(dev, s); } DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n"); return ret;}/*==============================================================================*/static int check_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist, int frontadd, int backadd){ unsigned int i, differencial=0, bipolar=0; /* correct channel and range number check itself comedi/range.c */ if (n_chan<1) { comedi_error(dev,"range/channel list is empty!"); return 0; } if ((frontadd+n_chan+backadd)>s->len_chanlist) { rt_printk("comedi%d: range/channel list is too long for actual configuration (%d>%d)!",dev->minor,n_chan,s->len_chanlist-frontadd-backadd); return 0; } if (CR_AREF(chanlist[0])==AREF_DIFF) differencial=1; // all input must be diff if (CR_RANGE(chanlist[0])<PCI9118_BIPOLAR_RANGES) bipolar=1; // all input must be bipolar if (n_chan > 1) for (i=1 ; i<n_chan; i++) { // check S.E/diff if ((CR_AREF(chanlist[i])==AREF_DIFF)!=(differencial)) { comedi_error(dev,"Differencial and single ended inputs cann't be mixtured!"); return 0; } if ((CR_RANGE(chanlist[i])<PCI9118_BIPOLAR_RANGES)!=(bipolar)) { comedi_error(dev,"Bipolar and unipolar ranges cann't be mixtured!"); return 0; } if ((!devpriv->usemux)&(differencial)&(CR_CHAN(chanlist[i])>=this_board->n_aichand)) { comedi_error(dev,"If AREF_DIFF is used then is available only first 8 channels!"); return 0; } } return 1;}/*==============================================================================*/static int setup_channel_list(comedi_device * dev, comedi_subdevice * s, int n_chan, unsigned int *chanlist,int rot, int frontadd, int backadd, int usedma, char useeos){ unsigned int i, differencial=0, bipolar=0; unsigned int scanquad, gain,ssh=0x00; DPRINTK("adl_pci9118 EDBG: BGN: setup_channel_list(%d,.,%d,.,%d,%d,%d,%d)\n", dev->minor, n_chan, rot, frontadd, backadd, usedma); if (usedma==1) { rot=8; usedma=0; } if (usedma) usedma=1; if (CR_AREF(chanlist[0])==AREF_DIFF) differencial=1; // all input must be diff if (CR_RANGE(chanlist[0])<PCI9118_BIPOLAR_RANGES) bipolar=1; // all input must be bipolar // All is ok, so we can setup channel/range list if (!bipolar) { devpriv->AdControlReg|=AdControl_UniP; // set unibipolar } else { devpriv->AdControlReg&=((~AdControl_UniP)&0xff); // enable bipolar } if (differencial) { devpriv->AdControlReg|=AdControl_Diff; // enable diff inputs } else { devpriv->AdControlReg&=((~AdControl_Diff)&0xff); // set single ended inputs } outl(devpriv->AdControlReg, dev->iobase+PCI9118_ADCNTRL); // setup mode outl(2,dev->iobase+PCI9118_SCANMOD); // gods know why this sequence! outl(0,dev->iobase+PCI9118_SCANMOD); outl(1,dev->iobase+PCI9118_SCANMOD); #ifdef PCI9118_PARANOIDCHECK devpriv->chanlistlen=n_chan; for (i=0; i<(PCI9118_CHANLEN+1); i++) devpriv->chanlist[i]=0x55aa;#endif if (frontadd) { // insert channels for S&H ssh=devpriv->softsshsample; DPRINTK("FA: %04x: ",ssh); for (i=0; i<frontadd; i++) { // store range list to card scanquad=CR_CHAN(chanlist[0]); // get channel number; gain=CR_RANGE(chanlist[0]); // get gain number scanquad|=((gain & 0x03)<<8); outl(scanquad|ssh,dev->iobase+PCI9118_GAIN); DPRINTK("%02x ",scanquad|ssh); ssh=devpriv->softsshhold; } DPRINTK("\n "); } DPRINTK("SL: ",ssh); for (i=0; i<n_chan; i++) { // store range list to card scanquad=CR_CHAN(chanlist[i]); // get channel number;#ifdef PCI9118_PARANOIDCHECK devpriv->chanlist[i^usedma]=(scanquad & 0xf)<<rot;#endif gain=CR_RANGE(chanlist[i]); // get gain number scanquad|=((gain & 0x03)<<8); outl(scanquad|ssh,dev->iobase+PCI9118_GAIN); DPRINTK("%02x ",scanquad|ssh); } DPRINTK("\n "); if (backadd) { // insert channels for fit onto 32bit DMA DPRINTK("BA: %04x: ",ssh); for (i=0; i<backadd; i++) { // store range list to card scanquad=CR_CHAN(chanlist[0]); // get channel number; gain=CR_RANGE(chanlist[0]); // get gain number scanquad|=((gain & 0x03)<<8); outl(scanquad|ssh,dev->iobase+PCI9118_GAIN); DPRINTK("%02x ",scanquad|ssh); } DPRINTK("\n "); } #ifdef PCI9118_PARANOIDCHECK devpriv->chanlist[n_chan^usedma]=devpriv->chanlist[0^usedma]; // for 32bit oerations if (useeos) { for (i=1; i<n_chan; i++) { // store range list to card devpriv->chanlist[(n_chan+i)^usedma]= (CR_CHAN(chanlist[i]) & 0xf)<<rot; } devpriv->chanlist[(2*n_chan)^usedma]=devpriv->chanlist[0^usedma]; // for 32bit oerations useeos=2; } else { useeos=1; }#ifdef PCI9118_EXTDEBUG DPRINTK("CHL: "); for (i=0; i<=(useeos*n_chan); i++) { DPRINTK("%04x ",devpriv->chanlist[i]); } DPRINTK("\n ");#endif#endif outl(0,dev->iobase+PCI9118_SCANMOD); // close scan queue// comedi_udelay(100); // important delay, or first sample will be cripled DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n"); return 1; // we can serve this with scan logic}/*============================================================================== calculate 8254 divisors if they are used for dual timing*/static void pci9118_calc_divisors(char mode, comedi_device * dev, comedi_subdevice * s, unsigned int *tim1, unsigned int *tim2, unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, char usessh, unsigned int chnsshfront){ DPRINTK("adl_pci9118 EDBG: BGN: pci9118_calc_divisors(%d,%d,.,%u,%u,%u,%d,.,.,,%u,%u)\n", mode, dev->minor, *tim1, *tim2, flags, chans, usessh, chnsshfront); switch (mode) { case 1: case 4: if (*tim2<this_board->ai_ns_min) *tim2=this_board->ai_ns_min; i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,div1,div2,tim2,flags&TRIG_ROUND_NEAREST); DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u\n",devpriv->i8254_osc_base,*div1,*div2,*tim1); break; case 2: if (*tim2<this_board->ai_ns_min) *tim2=this_board->ai_ns_min; DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); *div1=*tim2/devpriv->i8254_osc_base; // convert timer (burst) DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); if (*div1<this_board->ai_pacer_min) *div1=this_board->ai_pacer_min; DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); *div2=*tim1/devpriv->i8254_osc_base; // scan timer DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); *div2=*div2/ *div1; // major timer is c1*c2 DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); if (*div2<chans) *div2=chans; DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); *tim2=*div1 * devpriv->i8254_osc_base; // real convert timer if (usessh & (chnsshfront==0)) // use BSSH signal if (*div2<(chans+2)) *div2=chans+2; DPRINTK("7 div1=%u div2=%u timer1=%u timer2=%u\n",*div1,*div2,*tim1,*tim2); *tim1= *div1 * *div2 * devpriv->i8254_osc_base; DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u timer2=%u\n",devpriv->i8254_osc_base,*div1,*div2,*tim1,*tim2); break; } DPRINTK("adl_pci9118 EDBG: END: pci9118_calc_divisors(%u,%u)\n", *div1, *div2);} /*==============================================================================*/static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) { outl(0x74, dev->iobase + PCI9118_CNTCTRL); outl(0xb4, dev->iobase + PCI9118_CNTCTRL);// outl(0x30, dev->iobase + PCI9118_CNTCTRL); comedi_udelay(1); if ((mode==1)||(mode==2)||(mode==4)) { outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2); outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2); outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1); outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1); }}/*==============================================================================*/static int pci9118_exttrg_add(comedi_device * dev, unsigned char source){ if (source>3) return -1; // incorrect source devpriv->exttrg_users|=(1<<source); devpriv->IntControlReg|=Int_DTrg; outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL); outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)|0x1f00, devpriv->iobase_a+AMCC_OP_REG_INTCSR); // allow INT in AMCC return 0;}/* ==============================================================================*/static int pci9118_exttrg_del(comedi_device * dev, unsigned char source){ if (source>3) return -1; // incorrect source devpriv->exttrg_users&=~(1<<source); if (!devpriv->exttrg_users) { // shutdown ext trg intterrupts devpriv->IntControlReg&=~Int_DTrg; if (!devpriv->IntControlReg) // all IRQ disabled outl(inl(devpriv->iobase_a+AMCC_OP_REG_INTCSR)&(~0x00001f00), devpriv->iobase_a+AMCC_OP_REG_INTCSR); // disable int in AMCC outl(devpriv->IntControlReg,dev->iobase+PCI9118_INTCTRL); } return 0;}/* =============================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -