From c07d20332cf486c029917b4a0e01600dd2357442 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 21 Jun 2001 17:53:48 +0000 Subject: [PATCH] Added COMEDI_INSN ioctl() --- comedi/comedi_fops.c | 300 +++++++++++++++++++++++++++---------------- 1 file changed, 192 insertions(+), 108 deletions(-) diff --git a/comedi/comedi_fops.c b/comedi/comedi_fops.c index 6662e26e..57b5d18c 100644 --- a/comedi/comedi_fops.c +++ b/comedi/comedi_fops.c @@ -59,6 +59,7 @@ static int do_unlock_ioctl(comedi_device *dev,unsigned int arg,void * file); static int do_cancel_ioctl(comedi_device *dev,unsigned int arg,void *file); static int do_cmdtest_ioctl(comedi_device *dev,void *arg,void *file); static int do_insnlist_ioctl(comedi_device *dev,void *arg,void *file); +static int do_insn_ioctl(comedi_device *dev,void *arg,void *file); static int do_poll_ioctl(comedi_device *dev,unsigned int subd,void *file); #ifdef CONFIG_COMEDI_TRIG @@ -119,6 +120,8 @@ static int comedi_ioctl(struct inode * inode,struct file * file, return do_cmdtest_ioctl(dev,(void *)arg,file); case COMEDI_INSNLIST: return do_insnlist_ioctl(dev,(void *)arg,file); + case COMEDI_INSN: + return do_insn_ioctl(dev,(void *)arg,file); case COMEDI_POLL: return do_poll_ioctl(dev,arg,file); default: @@ -536,6 +539,7 @@ copyback: } +static int parse_insn(comedi_device *dev,comedi_insn *insn,lsampl_t *data,void *file); /* * COMEDI_INSNLIST * synchronous instructions @@ -551,158 +555,238 @@ copyback: * writes: * data (for reads) */ +/* arbitrary limits */ +#define MAX_SAMPLES 256 +#define MAX_INSNS 10 static int do_insnlist_ioctl(comedi_device *dev,void *arg,void *file) { comedi_insnlist insnlist; - comedi_insn insn; - comedi_subdevice *s; - lsampl_t *data; - int i; + comedi_insn *insns = NULL; + lsampl_t *data = NULL; + int i = 0; int ret=0; if(copy_from_user(&insnlist,arg,sizeof(comedi_insnlist))) return -EFAULT; - if(insnlist.n_insns>=10) /* XXX */ + if(insnlist.n_insns>=MAX_INSNS) return -EINVAL; - data=kmalloc(sizeof(lsampl_t)*256,GFP_KERNEL); - if(!data) - return -ENOMEM; + data=kmalloc(sizeof(lsampl_t)*MAX_SAMPLES,GFP_KERNEL); + if(!data){ + ret = -ENOMEM; + goto error; + } + + insns=kmalloc(sizeof(comedi_insn)*insnlist.n_insns,GFP_KERNEL); + if(!insns){ + ret = -ENOMEM; + goto error; + } + + if(copy_from_user(insns,insnlist.insns,sizeof(comedi_insn)*insnlist.n_insns)){ + ret=-EFAULT; + goto error; + } for(i=0;iMAX_SAMPLES){ + ret=-EINVAL; goto error; } - if(insn.n>256){ + if(insns[i].insn&INSN_MASK_WRITE){ + if(copy_from_user(data,insns[i].data, + insns[i].n*sizeof(lsampl_t))){ + ret=-EFAULT; + goto error; + } + } + ret = parse_insn(dev,insns+i,data,file); + if(ret<0)goto error; + if(ret!=insns[i].n){ + printk("BUG: result of insn != insn.n\n"); ret=-EINVAL; goto error; } - if(insn.insn&INSN_MASK_WRITE){ - if(copy_from_user(data,insn.data,insn.n*sizeof(lsampl_t))){ + if(insns[i].insn&INSN_MASK_READ){ + if(copy_to_user(insns[i].data,data, + insns[i].n*sizeof(lsampl_t))){ ret=-EFAULT; goto error; } } - if(insn.insn&INSN_MASK_SPECIAL){ - /* a non-subdevice instruction */ + } - switch(insn.insn){ - case INSN_GTOD: - { - struct timeval tv; +error: + if(insns)kfree(insns); + if(data)kfree(data); - if(insn.n!=2){ - ret=-EINVAL; - goto error; - } + if(ret<0)return ret; + return i; +} - do_gettimeofday(&tv); - data[0]=tv.tv_sec; - data[1]=tv.tv_usec; - ret=2; +static int parse_insn(comedi_device *dev,comedi_insn *insn,lsampl_t *data,void *file) +{ + comedi_subdevice *s; + int ret = 0; + + if(insn->insn&INSN_MASK_SPECIAL){ + /* a non-subdevice instruction */ + switch(insn->insn){ + case INSN_GTOD: + { + struct timeval tv; + + if(insn->n!=2){ + ret=-EINVAL; break; } - case INSN_WAIT: - if(insn.n!=1 || data[0]>=100000){ - ret=-EINVAL; - break; - } - udelay(data[0]/1000); - ret=1; - break; - case INSN_INTTRIG: - if(insn.subdev>=dev->n_subdevices){ - DPRINTK("%d not useable subdevice\n",insn.subdev); - ret=-EINVAL; - goto error; - } - s=dev->subdevices+insn.subdev; - if(!s->async || !s->async->inttrig){ - DPRINTK("no async or no inttrig\n"); - ret=-EINVAL; - goto error; - } - ret = s->async->inttrig(dev,s,0); + + do_gettimeofday(&tv); + data[0]=tv.tv_sec; + data[1]=tv.tv_usec; + ret=2; + + break; + } + case INSN_WAIT: + if(insn->n!=1 || data[0]>=100000){ + ret=-EINVAL; break; - default: - DPRINTK("invalid insn\n"); + } + udelay(data[0]/1000); + ret=1; + break; + case INSN_INTTRIG: + if(insn->subdev>=dev->n_subdevices){ + DPRINTK("%d not useable subdevice\n",insn->subdev); ret=-EINVAL; + break; } - }else{ - /* a subdevice instruction */ - if(insn.subdev>=dev->n_subdevices){ + s=dev->subdevices+insn->subdev; + if(!s->async || !s->async->inttrig){ + DPRINTK("no async or no inttrig\n"); ret=-EINVAL; - goto error; + break; } - s=dev->subdevices+insn.subdev; + ret = s->async->inttrig(dev,s,0); + break; + default: + DPRINTK("invalid insn\n"); + ret=-EINVAL; + } + }else{ + /* a subdevice instruction */ + if(insn->subdev>=dev->n_subdevices){ + ret=-EINVAL; + goto out; + } + s=dev->subdevices+insn->subdev; + + if(s->type==COMEDI_SUBD_UNUSED){ + DPRINTK("%d not useable subdevice\n",insn->subdev); + ret = -EIO; + goto out; + } - if(s->type==COMEDI_SUBD_UNUSED){ - DPRINTK("%d not useable subdevice\n",insn.subdev); - ret = -EIO; - goto error; - } - - /* are we locked? (ioctl lock) */ - if(s->lock && s->lock!=file){ - DPRINTK("device locked\n"); - ret = -EACCES; - goto error; - } + /* are we locked? (ioctl lock) */ + if(s->lock && s->lock!=file){ + DPRINTK("device locked\n"); + ret = -EACCES; + goto out; + } - if((ret=check_chanlist(s,1,&insn.chanspec))<0){ - ret=-EINVAL; - DPRINTK("bad chanspec\n"); - goto error; - } + if((ret=check_chanlist(s,1,&insn->chanspec))<0){ + ret=-EINVAL; + DPRINTK("bad chanspec\n"); + goto out; + } - if(s->busy){ - ret=-EBUSY; - goto error; - } - s->busy=file; - - switch(insn.insn){ - case INSN_READ: - ret=s->insn_read(dev,s,&insn,data); - break; - case INSN_WRITE: - ret=s->insn_write(dev,s,&insn,data); - break; - case INSN_BITS: - ret=s->insn_bits(dev,s,&insn,data); - break; - case INSN_CONFIG: - ret=s->insn_config(dev,s,&insn,data); - break; - default: - ret=-EINVAL; - break; - } + if(s->busy){ + ret=-EBUSY; + goto out; + } + /* This looks arbitrary. It is. */ + s->busy=&parse_insn; - s->busy=NULL; + switch(insn->insn){ + case INSN_READ: + ret=s->insn_read(dev,s,insn,data); + break; + case INSN_WRITE: + ret=s->insn_write(dev,s,insn,data); + break; + case INSN_BITS: + ret=s->insn_bits(dev,s,insn,data); + break; + case INSN_CONFIG: + ret=s->insn_config(dev,s,insn,data); + break; + default: + ret=-EINVAL; + break; } - if(ret<0)goto error; - if(ret!=insn.n){ - printk("BUG: result of insn != insn.n\n"); - ret=-EINVAL; + + s->busy=NULL; + } + +out: + return ret; +} + +/* + * COMEDI_INSN + * synchronous instructions + * + * arg: + * pointer to insn + * + * reads: + * comedi_insn struct at arg + * data (for writes) + * + * writes: + * data (for reads) + */ +static int do_insn_ioctl(comedi_device *dev,void *arg,void *file) +{ + comedi_insn insn; + lsampl_t *data = NULL; + int ret=0; + + data=kmalloc(sizeof(lsampl_t)*MAX_SAMPLES,GFP_KERNEL); + if(!data){ + ret = -ENOMEM; + goto error; + } + + if(copy_from_user(&insn,arg,sizeof(comedi_insn))){ + ret=-EFAULT; + goto error; + } + + /* This is where the behavior of insn and insnlist deviate. */ + if(insn.n>MAX_SAMPLES)insn.n=MAX_SAMPLES; + if(insn.insn&INSN_MASK_WRITE){ + if(copy_from_user(data,insn.data,insn.n*sizeof(lsampl_t))){ + ret=-EFAULT; goto error; } - if(insn.insn&INSN_MASK_READ){ - if(copy_to_user(insn.data,data,insn.n*sizeof(lsampl_t))){ - ret=-EFAULT; - goto error; - } + } + ret = parse_insn(dev,&insn,data,file); + if(ret<0)goto error; + if(insn.insn&INSN_MASK_READ){ + if(copy_to_user(insn.data,data,insn.n*sizeof(lsampl_t))){ + ret=-EFAULT; + goto error; } } error: - kfree(data); + if(data)kfree(data); - if(i==0)return ret; - return i; + return ret; } /* -- 2.26.2