📄 kcomedilib_main.c
字号:
/* kcomedilib/kcomedilib.c a comedlib interface for kernel modules COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#define __NO_VERSION__#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/fcntl.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/slab.h>#include <asm/io.h>#include <linux/comedidev.h>#include <linux/comedi.h>#include <linux/comedilib.h>MODULE_AUTHOR("David Schleef <ds@schleef.org>");MODULE_DESCRIPTION("Comedi kernel library");MODULE_LICENSE("GPL");comedi_t *comedi_open(const char *filename){ comedi_device *dev; unsigned int minor; if(strncmp(filename,"/dev/comedi",11) != 0) return NULL; minor = simple_strtoul(filename+11,NULL,0); if(minor >= COMEDI_NDEVICES) return NULL; dev = comedi_get_device_by_minor(minor); if(!dev->attached) return NULL; __MOD_INC_USE_COUNT(dev->driver->module); return (comedi_t *)dev;}comedi_t *comedi_open_old(unsigned int minor){ comedi_device *dev; if(minor>=COMEDI_NDEVICES) return NULL; dev = comedi_get_device_by_minor(minor); if(!dev->attached) return NULL; return (comedi_t *)dev;}int comedi_close(comedi_t *d){ comedi_device *dev = (comedi_device *) d; __MOD_DEC_USE_COUNT(dev->driver->module); return 0;}int comedi_loglevel(int newlevel){ return 0;}void comedi_perror(const char *message){ rt_printk("%s: unknown error\n",message);}char *comedi_strerror(int err){ return "unknown error";}int comedi_fileno(comedi_t *d){ comedi_device *dev = (comedi_device *)d; /* return something random */ return dev->minor;}static void init_async_buf( comedi_async *async ){ async->buf_read_count = 0; async->buf_write_count = 0; async->buf_write_alloc_count = 0; async->buf_read_ptr = 0; async->buf_write_ptr = 0; async->cur_chan = 0; async->scan_progress = 0; async->munge_chan = 0;}int comedi_command(comedi_t *d,comedi_cmd *cmd){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s; comedi_async *async; if(cmd->subdev>=dev->n_subdevices) return -ENODEV; s=dev->subdevices+cmd->subdev; if(s->type==COMEDI_SUBD_UNUSED) return -EIO; async = s->async; if(async == NULL) return -ENODEV; async->cb_mask |= COMEDI_CB_EOA|COMEDI_CB_BLOCK|COMEDI_CB_ERROR; async->cmd=*cmd;#if 0 s->runflags=0;#else s->runflags=SRF_RT; comedi_switch_to_rt(dev);#endif s->subdev_flags |= SDF_RUNNING; init_async_buf( async ); return s->do_cmd(dev,s);}int comedi_command_test(comedi_t *d,comedi_cmd *cmd){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s; if(cmd->subdev>=dev->n_subdevices) return -ENODEV; s=dev->subdevices+cmd->subdev; if(s->type==COMEDI_SUBD_UNUSED) return -EIO; if(s->async == NULL) return -ENODEV; return s->do_cmdtest(dev,s,cmd);}/* * COMEDI_INSN * perform an instruction */int comedi_do_insn(comedi_t *d,comedi_insn *insn){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s; int ret=0; if(insn->insn&INSN_MASK_SPECIAL){ switch(insn->insn){ case INSN_GTOD: { struct timeval tv; lsampl_t data[2]; do_gettimeofday(&tv); data[0] = tv.tv_sec; data[1] = tv.tv_usec; ret = 2; break; } case INSN_WAIT: if(insn->n<1 || insn->data[0]>=100){ ret = -EINVAL; break; } comedi_udelay(insn->data[0]); ret=1; break; case INSN_INTTRIG: if(insn->n!=1){ ret=-EINVAL; break; } if(insn->subdev>=dev->n_subdevices){ rt_printk("%d not usable subdevice\n",insn->subdev); ret=-EINVAL; break; } s=dev->subdevices+insn->subdev; if(!s->async){ rt_printk("no async\n"); ret=-EINVAL; break; } if(!s->async->inttrig){ rt_printk("no inttrig\n"); ret=-EAGAIN; break; } ret = s->async->inttrig(dev,s,insn->data[0]); if(ret>=0)ret = 1; break; default: ret = -EINVAL; } }else{ /* a subdevice instruction */ if(insn->subdev>=dev->n_subdevices){ ret = -EINVAL; goto error; } s = dev->subdevices+insn->subdev; if(s->type==COMEDI_SUBD_UNUSED){ rt_printk("%d not useable subdevice\n",insn->subdev); /* XXX no return value is set! ret = ? */ goto error; } /* XXX check lock */ if((ret=check_chanlist(s,1,&insn->chanspec))<0){ rt_printk("bad chanspec\n"); /* XXX no return value is set! ret = ? */ goto error; } if(s->busy){ ret = -EBUSY; goto error; } s->busy = d; switch(insn->insn){ case INSN_READ: ret = s->insn_read(dev,s,insn,insn->data); break; case INSN_WRITE: ret = s->insn_write(dev,s,insn,insn->data); break; case INSN_BITS: ret = s->insn_bits(dev,s,insn,insn->data); break; case INSN_CONFIG: ret = s->insn_config(dev,s,insn,insn->data); break; default: ret=-EINVAL; break; } s->busy = NULL; } if(ret<0)goto error; if(ret!=insn->n){ rt_printk("BUG: result of insn != insn.n\n"); ret = -EINVAL; goto error; }error: return ret;}/* COMEDI_LOCK lock subdevice arg: subdevice number reads: none writes: none necessary locking: - ioctl/rt lock (this type) - lock while subdevice busy - lock while subdevice being programmed*/int comedi_lock(comedi_t *d,unsigned int subdevice){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; unsigned long flags; int ret=0; comedi_spin_lock_irqsave(&big_comedi_lock,flags); if(s->busy){ ret = -EBUSY; }else{ if(s->lock && s->lock!=d){ ret = -EACCES; }else{ s->lock = d; } } comedi_spin_unlock_irqrestore(&big_comedi_lock,flags); return ret;}/* COMEDI_UNLOCK unlock subdevice arg: subdevice number reads: none writes: none*/int comedi_unlock(comedi_t *d,unsigned int subdevice){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; unsigned long flags; comedi_async *async; async = s->async; comedi_spin_lock_irqsave(&big_comedi_lock,flags); if(s->busy){ comedi_spin_unlock_irqrestore(&big_comedi_lock,flags); return -EBUSY; } if(s->lock && s->lock!=(void *)d){ comedi_spin_unlock_irqrestore(&big_comedi_lock,flags); return -EACCES; } s->lock=NULL; if(async){ async->cb_mask=0; async->cb_func=NULL; async->cb_arg=NULL; } comedi_spin_unlock_irqrestore(&big_comedi_lock,flags); return 0;}/* COMEDI_CANCEL cancel acquisition ioctl arg: subdevice number reads: nothing writes: nothing*/int comedi_cancel(comedi_t *d,unsigned int subdevice){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; int ret=0; if(s->lock && s->lock!=d) return -EACCES;#if 0 if(!s->busy) return 0; if(s->busy!=d) return -EBUSY;#endif if(!s->cancel) return -EINVAL; if((ret=s->cancel(dev,s))) return ret; if( s->runflags & SRF_RT ) { // XXX race s->runflags &= ~SRF_RT; comedi_switch_to_non_rt(dev); } s->busy=NULL; return 0;}/* registration of callback functions */int comedi_register_callback(comedi_t *d,unsigned int subdevice, unsigned int mask,int (*cb)(unsigned int,void *),void *arg){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; comedi_async *async; async = s->async; if(s->type==COMEDI_SUBD_UNUSED) return -EIO; /* are we locked? (ioctl lock) */ if(s->lock && s->lock!=d) return -EACCES; /* are we busy? */ if(s->busy) return -EBUSY; if(!mask){ async->cb_mask=0; async->cb_func=NULL; async->cb_arg=NULL; }else{ async->cb_mask=mask; async->cb_func=cb; async->cb_arg=arg; } return 0;}int comedi_poll(comedi_t *d, unsigned int subdevice){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; comedi_async *async; async = s->async; if(s->type==COMEDI_SUBD_UNUSED || !async) return -EIO; /* are we locked? (ioctl lock) */ if(s->lock && s->lock!=d) return -EACCES; /* are we running? XXX wrong? */ if(!s->busy) return -EIO; return s->poll(dev,s);}/* WARNING: not portable */int comedi_map(comedi_t *d, unsigned int subdevice, void *ptr){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; if(!s->async) return -EINVAL; if(ptr) { *((void **) ptr) = s->async->prealloc_buf; } /* XXX no reference counting */ return 0;}/* WARNING: not portable */int comedi_unmap(comedi_t *d, unsigned int subdevice){ comedi_device *dev = (comedi_device *)d; comedi_subdevice *s = dev->subdevices + subdevice; if(!s->async) return -EINVAL; /* XXX no reference counting */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -