📄 amplc_pci230.c
字号:
* deallocated automatically by the core. */static int pci230_detach(comedi_device *dev){ printk("comedi%d: amplc_pci230: remove\n",dev->minor); if(dev->subdevices && thisboard->have_dio) subdev_8255_cleanup(dev,dev->subdevices + 2); /* Clean up dio subdevice. */ if(dev->iobase) release_region(dev->iobase,PCI230_IO2_SIZE); if(dev->irq) comedi_free_irq(dev->irq, dev); if(devpriv){ if(devpriv->pci_iobase){ release_region(devpriv->pci_iobase, PCI230_IO1_SIZE); } } return 0;}/* * COMEDI_SUBD_AI instruction; */ static int pci230_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int n,i; int chan, range, aref; unsigned int status; unsigned int adccon, adcen, adcg; /* Unpack channel and range. */ chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); aref = CR_AREF(insn->chanspec); /* If bit 2 of range unset, range is referring to bipolar element in range table */ adccon = PCI230_ADC_TRIG_SW | PCI230_ADC_FIFO_RESET; devpriv->ai_bipolar = !PCI230_TEST_BIT(range, 2); if (aref==AREF_DIFF) { /* Differential. */ adcen = 3<<2*chan; adccon |= PCI230_ADC_IM_DIF; if (devpriv->ai_bipolar) { adccon |= PCI230_ADC_IR_BIP; adcg = range<<(2*chan-2*chan%2); } else { adccon |= PCI230_ADC_IR_UNI; adcg = ((range&(~4))+1)<<(2*chan-2*chan%2); } } else { /* Single ended. */ adcen = 1<<chan; adccon |= PCI230_ADC_IM_SE; if (devpriv->ai_bipolar) { adccon |= PCI230_ADC_IR_BIP; adcg = range<<(chan-chan%2); } else { adccon |= PCI230_ADC_IR_UNI; adcg = ((range&(~4))+1)<<(chan-chan%2); } } /* Enable only this channel in the scan list - otherwise by default we'll get one sample from each channel. */ outw_p(adcen, dev->iobase + PCI230_ADCEN); /* Set gain for channel. */ outw_p(adcg, dev->iobase + PCI230_ADCG); /* Specify uni/bip, se/diff, s/w conversion, and reset FIFO (even though we're not using it - MEV says so). */ outw_p(adccon, dev->iobase + PCI230_ADCCON); /* Convert n samples */ for(n=0;n<insn->n;n++){ /* trigger conversion */ outw_p(PCI230_ADC_CONV,dev->iobase + PCI230_ADCDATA);#define TIMEOUT 100 /* wait for conversion to end */ for(i=0;i<TIMEOUT;i++){ status = inw(dev->iobase + PCI230_ADCCON); if(PCI230_TEST_BIT(status, PCI230_ADC_BUSY_BIT))break; } if(i==TIMEOUT){ /* rt_printk() should be used instead of printk() * whenever the code can be called from real-time. */ rt_printk("timeout\n"); return -ETIMEDOUT; } /* read data */ data[n] = pci230_ai_read(dev); } /* return the number of samples read/written */ return n;}/* * COMEDI_SUBD_AO instructions; */ static int pci230_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan, range; /* Unpack channel and range. */ chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); /* Set range - see analogue output range table; 0 => unipolar 10V, 1 => bipolar +/-10V range scale */ devpriv->ao_bipolar = PCI230_TEST_BIT(range, PCI230_DAC_BIP_BIT); outw(range, dev->iobase + PCI230_DACCON); /* Writing a list of values to an AO channel is probably not * very useful, but that's how the interface is defined. */ for(i=0;i<insn->n;i++){ /* Store the value to be written to the DAC in our pci230_private struct before mangling it. */ devpriv->ao_readback[chan] = data[i]; /* Write value to DAC. */ pci230_ao_write(dev, data[i], chan); } /* return the number of samples read/written */ return i;}/* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */static int pci230_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan = CR_CHAN(insn->chanspec); for(i=0;i<insn->n;i++) data[i] = devpriv->ao_readback[chan]; return i;}/* * COMEDI_SUBD_TIMER instructions; * * insn_config allows user to start and stop counter/timer 2 (SK1 pin 21). * Period specified in ns. * * rinsn returns counter/timer's actual period in ns. */static int pci230_ct_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ unsigned int ns; if(insn->n!=1)return -EINVAL; ns = data[0]; if (ns == 0) { //Stop counter/timer 2. pci230_cancel_ct2(dev); } else { //Start conter/timer 2 with period ns. pci230_z2_ct2(dev, &ns, TRIG_ROUND_MASK); } return 1;}static int pci230_ct_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ if(insn->n!=1)return -EINVAL; /* Return the actual period set in ns. */ data[0] = PCI230_TIMEBASE_10MHZ*devpriv->divisor1*devpriv->divisor2; return 1;}static int pci230_ao_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){ int err=0; int tmp; /* cmdtest tests a particular command to see if it is valid. * Using the cmdtest ioctl, a user can create a valid cmd * and then have it executes by the cmd ioctl. * * cmdtest returns 1,2,3,4 or 0, depending on which tests * the command passes. */ /* Step 1: make sure trigger sources are trivially valid. * "invalid source" returned by comedilib to user mode process * if this fails. */ 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_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 * "source conflict" returned by comedilib to user mode process * if this fails. */ if(cmd->stop_src!=TRIG_COUNT && cmd->stop_src!=TRIG_NONE)err++; if(err)return 2; /* Step 3: make sure arguments are trivially compatible. * "invalid argument" returned by comedilib to user mode process * if this fails. */ if(cmd->start_arg!=0){ cmd->start_arg=0; err++; }#define MAX_SPEED 3205 /* 3205ns => 312kHz */#define MIN_SPEED 4294967295u /* 4294967295ns = 4.29s - Comedi limit due to unsigned int cmd. Driver limit = 2^32 (2 cascaded 16bit counters) * 100ns (default 10MHz onboard clock) = 429s */ if(cmd->scan_begin_src==TRIG_TIMER){ if(cmd->scan_begin_arg<MAX_SPEED){ cmd->scan_begin_arg=MAX_SPEED; err++; } if(cmd->scan_begin_arg>MIN_SPEED){ cmd->scan_begin_arg=MIN_SPEED; err++; } } if(cmd->scan_end_arg!=cmd->chanlist_len){ cmd->scan_end_arg=cmd->chanlist_len; err++; } if(cmd->stop_src==TRIG_NONE){ /* TRIG_NONE */ if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } } if(err)return 3; /* Step 4: fix up any arguments. * "argument conflict" returned by comedilib to user mode process * if this fails. */ if(cmd->scan_begin_src==TRIG_TIMER){ tmp=cmd->scan_begin_arg; pci230_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 pci230_ao_inttrig(comedi_device *dev,comedi_subdevice *s, unsigned int trig_num){ if(trig_num != 0) return -EINVAL; /* Enable DAC interrupt. */ devpriv->ier |= PCI230_INT_ZCLK_CT1; outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE); s->async->inttrig=NULL; return 1;}static int pci230_ao_cmd(comedi_device *dev,comedi_subdevice *s){ int range; /* Get the command. */ comedi_cmd *cmd=&s->async->cmd; /* Calculate number of conversions required. */ if(cmd->stop_src == TRIG_COUNT) { devpriv->ao_count = cmd->stop_arg * cmd->chanlist_len; devpriv->ao_stop = 0; } else { /* TRIG_NONE, user calls cancel. */ devpriv->ao_count = 0; devpriv->ao_stop = 1; } /* Disable DAC interrupt. */ devpriv->ier &= ~PCI230_INT_ZCLK_CT1; outb(devpriv->ier, devpriv->pci_iobase + PCI230_INT_SCE); /* Set range - see analogue output range table; 0 => unipolar 10V, 1 => bipolar +/-10V range scale */ range = CR_RANGE(cmd->chanlist[0]); devpriv->ao_bipolar = PCI230_TEST_BIT(range, PCI230_DAC_BIP_BIT); outw(range, dev->iobase + PCI230_DACCON); /* Set the counter timers to the specified sampling frequency. * TODO - when Comedi supports concurrent commands, this must be * changed; using ct0 and ct1 for DAC will screw up ADC pacer * which uses ct2 and ct0. Change to only use ct1 for DAC? */ pci230_z2_ct1(dev, &cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); /* cmd->convert_arg is sampling period in ns */ s->async->inttrig=pci230_ao_inttrig; return 0;}static int pci230_ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){ int err=0; int tmp; /* cmdtest tests a particular command to see if it is valid. * Using the cmdtest ioctl, a user can create a valid cmd * and then have it executes by the cmd ioctl. * * cmdtest returns 1,2,3,4 or 0, depending on which tests * the command passes. */ /* Step 1: make sure trigger sources are trivially valid. * "invalid source" returned by comedilib to user mode process * if this fails. */ 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; cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 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 * "source conflict" returned by comedilib to user mode process * if this fails. */ if(cmd->start_src!=TRIG_NOW)err++; if(cmd->scan_begin_src!=TRIG_FOLLOW)err++; if(cmd->convert_src!=TRIG_TIMER && cmd->convert_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. * "invalid argument" returned by comedilib to user mode process * if this fails. */ if(cmd->start_arg!=0){ cmd->start_arg=0; err++; }#define MAX_SPEED 3205 /* 3205ns => 312kHz max sampling - claimed max for single channel; should really be fn(nchans) */#define MIN_SPEED 4294967295u /* 4294967295ns = 4.29s - Comedi limit due to unsigned int cmd. Driver limit = 2^32 (2 cascaded 16bit counters) * 100ns (default 10MHz onboard clock) = 429s */ if(cmd->convert_src==TRIG_TIMER){ if(cmd->convert_arg<MAX_SPEED){ cmd->convert_arg=MAX_SPEED; err++; } if(cmd->convert_arg>MIN_SPEED){ cmd->convert_arg=MIN_SPEED; err++; } }else{ /* external trigger */ /* convert_arg == 0 => trigger on -ve edge. */ /* convert_arg == 1 => trigger on +ve edge. */ if(cmd->convert_arg>1){ cmd->convert_arg=1; /* Default to trigger on +ve edge. */ err++; } } if(cmd->scan_end_arg!=cmd->chanlist_len){ cmd->scan_end_arg=cmd->chanlist_len; err++; } if(cmd->stop_src==TRIG_NONE){ /* TRIG_NONE */ if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } } if(err)return 3; /* Step 4: fix up any arguments. * "argument conflict" returned by comedilib to user mode process * if this fails. */ if(cmd->convert_src==TRIG_TIMER){ tmp=cmd->convert_arg; pci230_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -