📄 skel.c
字号:
* "instructions" read/write data in "one-shot" or "software-triggered" * mode. */static int skel_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int n,i; unsigned int d; unsigned int status; /* a typical programming sequence */ /* write channel to multiplexer */ //outw(chan,dev->iobase + SKEL_MUX); /* don't wait for mux to settle */ /* convert n samples */ for(n=0;n<insn->n;n++){ /* trigger conversion */ //outw(0,dev->iobase + SKEL_CONVERT);#define TIMEOUT 100 /* wait for conversion to end */ for(i=0;i<TIMEOUT;i++){ status = 1; //status = inb(dev->iobase + SKEL_STATUS); if(status)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 */ //d = inw(dev->iobase + SKEL_AI_DATA); d = 0; /* mangle the data as necessary */ d ^= 1<<(thisboard->ai_bits-1); data[n] = d; } /* return the number of samples read/written */ return n;}static int skel_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 */ 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_TIMER|TRIG_EXT; 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 */ /* note that mutual compatiblity is not an issue here */ if(cmd->scan_begin_src!=TRIG_TIMER && cmd->scan_begin_src!=TRIG_EXT)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 */ if(cmd->start_arg!=0){ cmd->start_arg=0; err++; }#define MAX_SPEED 10000 /* in nanoseconds */#define MIN_SPEED 1000000000 /* in nanoseconds */ 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++; } }else{ /* external trigger */ /* should be level/edge, hi/lo specification here */ /* should specify multiple external triggers */ if(cmd->scan_begin_arg>9){ cmd->scan_begin_arg=9; err++; } } 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 */ /* see above */ if(cmd->convert_arg>9){ cmd->convert_arg=9; 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>0x00ffffff){ cmd->stop_arg=0x00ffffff; 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->scan_begin_src==TRIG_TIMER){ tmp=cmd->scan_begin_arg; skel_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->scan_begin_arg)err++; } if(cmd->convert_src==TRIG_TIMER){ tmp=cmd->convert_arg; skel_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->convert_arg)err++; if(cmd->scan_begin_src==TRIG_TIMER && cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){ cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg; err++; } } if(err)return 4; return 0;}/* This function doesn't require a particular form, this is just * what happens to be used in some of the drivers. It should * convert ns nanoseconds to a counter value suitable for programming * the device. Also, it should adjust ns so that it cooresponds to * the actual time that the device will use. */static int skel_ns_to_timer(unsigned int *ns,int round){ /* trivial timer */ /* if your timing is done through two cascaded timers, the * i8253_cascade_ns_to_timer() function in 8253.h can be * very helpful. There are also i8254_load() and i8254_mm_load() * which can be used to load values into the ubiquitous 8254 counters */ return *ns;}static int skel_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan = CR_CHAN(insn->chanspec);printk("skel_ao_winsn\n"); /* 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++){ /* a typical programming sequence */ //outw(data[i],dev->iobase + SKEL_DA0 + chan); devpriv->ao_readback[chan] = data[i]; } /* 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 skel_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;}/* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */static int skel_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; /* The insn data is a mask in data[0] and the new data * in data[1], each channel cooresponding to a bit. */ if(data[0]){ s->state &= ~data[0]; s->state |= data[0]&data[1]; /* Write out the new digital output lines */ //outw(s->state,dev->iobase + SKEL_DIO); } /* on return, data[1] contains the value of the digital * input and output lines. */ //data[1]=inw(dev->iobase + SKEL_DIO); /* or we could just return the software copy of the output values if * it was a purely digital output subdevice */ //data[1]=s->state; return 2;}static int skel_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int chan=CR_CHAN(insn->chanspec); if(insn->n!=1)return -EINVAL; /* The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the * value COMEDI_INPUT or COMEDI_OUTPUT. */ if(data[0]==COMEDI_OUTPUT){ s->io_bits |= 1<<chan; }else{ s->io_bits &= ~(1<<chan); } //outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); return 1;}/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_skel);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -