From e1e8b27955b4686517be3a36b5f453974b4a2226 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 15 Jun 2000 05:10:19 +0000 Subject: [PATCH] insn support, rt virtualization, runflags --- comedi/comedi_fops.c | 190 ++++++++++++++++++++++++++++++++--------- comedi/comedi_module.h | 12 ++- comedi/comedi_rt.h | 10 ++- comedi/drivers.c | 51 +++++++++++ 4 files changed, 214 insertions(+), 49 deletions(-) diff --git a/comedi/comedi_fops.c b/comedi/comedi_fops.c index 0727102b..aaf8ee6f 100644 --- a/comedi/comedi_fops.c +++ b/comedi/comedi_fops.c @@ -53,6 +53,7 @@ static int do_lock_ioctl(comedi_device *dev,unsigned int arg,void * file); 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 void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s); @@ -85,6 +86,8 @@ static int comedi_ioctl(struct inode * inode,struct file * file,unsigned int cmd return do_cmd_ioctl(dev,(void *)arg,file); case COMEDI_CMDTEST: return do_cmdtest_ioctl(dev,(void *)arg,file); + case COMEDI_INSNLIST: + return do_insnlist_ioctl(dev,(void *)arg,file); default: return -EIO; } @@ -349,7 +352,7 @@ DPRINTK("entering do_trig_ioctl()\n"); s=dev->subdevices+user_trig.subdev; if(s->type==COMEDI_SUBD_UNUSED){ - DPRINTK("%d not used device\n",user_trig.subdev); + DPRINTK("%d not useable subdevice\n",user_trig.subdev); return -EIO; } @@ -458,20 +461,7 @@ static int do_trig_ioctl_mode0(comedi_device *dev,comedi_subdevice *s,comedi_tri } } - if(s->cur_trig.mode>=5 || s->trig[s->cur_trig.mode]==NULL){ - DPRINTK("bad mode %d\n",s->cur_trig.mode); - ret=-EINVAL; - goto cleanup; - } - - /* mark as non-RT operation */ - s->cur_trig.flags &= ~TRIG_RT; - - s->subdev_flags|=SDF_RUNNING; - - ret=s->trig[s->cur_trig.mode](dev,s,&s->cur_trig); - - if(ret==0)return 0; + ret=s->trig[0](dev,s,&s->cur_trig); if(ret<0)goto cleanup; @@ -563,6 +553,146 @@ cleanup: } +/* + * COMEDI_INSNLIST + * synchronous instructions + * + * arg: + * pointer to sync cmd structure + * + * reads: + * sync cmd struct at arg + * instruction list + * data (for writes) + * + * writes: + * data (for reads) + */ +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; + int ret=0; + + if(copy_from_user(&insnlist,arg,sizeof(comedi_insnlist))) + return -EFAULT; + + if(insnlist.n_insns>=10) + return -EINVAL; + + data=kmalloc(sizeof(lsampl_t)*256,GFP_KERNEL); + if(!data) + return -ENOMEM; + + for(i=0;i256){ + ret=-EINVAL; + break; + } + if(insn.insn&INSN_MASK_WRITE){ + if(copy_from_user(data,insn.data,insn.n*sizeof(lsampl_t))){ + ret=-EFAULT; + break; + } + } + if(insn.insn&INSN_MASK_SPECIAL){ + /* a non-subdevice instruction */ + + switch(insn.insn){ + case INSN_GTOD: + { + struct timeval tv; + + 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]>=100){ + ret=-EINVAL; + break; + } + udelay(data[0]); + ret=1; + break; + default: + ret=-EINVAL; + } + }else{ + /* a subdevice instruction */ + if(insn.subdev>=dev->n_subdevices){ + ret=-EINVAL; + break; + } + s=dev->subdevices+insn.subdev; + + if(s->type==COMEDI_SUBD_UNUSED){ + DPRINTK("%d not useable subdevice\n",insn.subdev); + return -EIO; + } + + /* are we locked? (ioctl lock) */ + if(s->lock && s->lock!=file){ + DPRINTK("device locked\n"); + return -EACCES; + } + + if(s->busy){ + ret=-EBUSY; + break; + } + s->busy=file; + + if((ret=check_chanlist(s,1,&insn.chanspec))<0){ + ret=-EINVAL; + DPRINTK("bad chanspec\n"); + break; + } + + 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; + default: + ret=-EINVAL; + break; + } + + s->busy=NULL; + } + if(ret<0)break; + if(ret!=insn.n){ + printk("result of insn != insn.n\n"); + ret=-EINVAL; + break; + } + if(insn.insn&INSN_MASK_READ){ + if(copy_to_user(insn.data,data,insn.n*sizeof(lsampl_t))){ + ret=-EFAULT; + break; + } + } + } + + kfree(data); + + if(i==0)return ret; + return i; +} + /* COMEDI_CMD command ioctl @@ -1409,19 +1539,8 @@ int init_module(void) /* XXX requires /proc interface */ comedi_proc_init(); -#ifdef CONFIG_COMEDI_RTL - comedi_rtl_init(); -#endif -#ifdef CONFIG_COMEDI_RTL_V1 - comedi_rtlv1_init(); -#endif -#ifdef CONFIG_COMEDI_RTAI - comedi_rtai_init(); -#endif -#if 0 -#ifdef CONFIG_COMEDI_MITE - mite_init(); -#endif +#ifdef CONFIG_COMEDI_RT + comedi_rt_init(); #endif init_drivers(); @@ -1450,19 +1569,8 @@ void cleanup_module(void) } kfree(comedi_devices); -#ifdef CONFIG_COMEDI_RTL - comedi_rtl_cleanup(); -#endif -#ifdef CONFIG_COMEDI_RTL_V1 - comedi_rtlv1_cleanup(); -#endif -#ifdef CONFIG_COMEDI_RTAI - comedi_rtai_cleanup(); -#endif -#if 0 -#ifdef CONFIG_COMEDI_MITE - mite_cleanup(); -#endif +#ifdef CONFIG_COMEDI_RT + comedi_rt_cleanup(); #endif } diff --git a/comedi/comedi_module.h b/comedi/comedi_module.h index ed3a175a..a944b412 100644 --- a/comedi/comedi_module.h +++ b/comedi/comedi_module.h @@ -65,6 +65,7 @@ struct comedi_subdevice_struct{ void *lock; void *busy; + unsigned int runflags; int io_bits; @@ -88,12 +89,11 @@ struct comedi_subdevice_struct{ unsigned int buf_user_count; /* byte count for read() and write() */ unsigned int cur_chan; /* useless channel marker for interrupt */ -#if 0 - unsigned int *range_list; /* is this necessary? */ -#endif - int (*trig[5])(comedi_device *,comedi_subdevice *,comedi_trig *); + int (*insn_read)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *data); + int (*insn_write)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *data); + int (*do_cmd)(comedi_device *,comedi_subdevice *); int (*do_cmdtest)(comedi_device *,comedi_subdevice *,comedi_cmd *); int (*poll)(comedi_device *,comedi_subdevice *); @@ -194,6 +194,10 @@ int do_pack(unsigned int *bits,comedi_trig *it); #endif +#define SRF_USER 0x00000001 +#define SRF_RT 0x00000002 +#define SRF_RTIRQ 0x00000004 + /* various internal comedi functions diff --git a/comedi/comedi_rt.h b/comedi/comedi_rt.h index b7803a01..04fed933 100644 --- a/comedi/comedi_rt.h +++ b/comedi/comedi_rt.h @@ -43,7 +43,7 @@ struct comedi_irq_struct{ void *dev_id; unsigned long flags; void (*handler)(int,void *,struct pt_regs *); - char *device; + const char *device; }; int get_priority_irq(struct comedi_irq_struct *); @@ -97,9 +97,11 @@ extern void wake_up_int_handler(int arg1, void * arg2); #define rt_printk_cleanup() #endif -int comedi_request_irq(unsigned int irq,void (*handler)(int,void *,struct pt_reg - unsigned long flags,const char *device,void *dev_id); -int comedi_change_irq_flags(unsigned int irq,void *dev_id,unsigned long new_flag +int comedi_request_irq(unsigned int irq,void (*handler)(int,void *, + struct pt_regs *regs),unsigned long flags,const char *device, + void *dev_id); +int comedi_change_irq_flags(unsigned int irq,void *dev_id, + unsigned long new_flags); void comedi_free_irq(unsigned int irq,void *dev_id); diff --git a/comedi/drivers.c b/comedi/drivers.c index 4d4f3fc7..6f474c45 100644 --- a/comedi/drivers.c +++ b/comedi/drivers.c @@ -40,6 +40,7 @@ static void postconfig(comedi_device *dev); static int command_trig(comedi_device *dev,comedi_subdevice *s,comedi_trig *it); static int mode_to_command(comedi_cmd *cmd,comedi_trig *it); +static int insn_emulate(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); comedi_driver *comedi_drivers; @@ -220,6 +221,9 @@ static void postconfig(comedi_device *dev) if(!s->range_table && !s->range_table_list) s->range_table=&range_unknown; + + if(!s->insn_read)s->insn_read=insn_emulate; + if(!s->insn_write)s->insn_write=insn_emulate; } } @@ -256,6 +260,53 @@ int do_pack(unsigned int *bits,comedi_trig *it) return i; } +static int insn_emulate(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) +{ + comedi_trig trig; + int i; + int ret; + + switch(insn->insn){ + case INSN_WRITE: + if(!(s->subdev_flags & SDF_WRITEABLE)) + return -EINVAL; + trig.flags=TRIG_WRITE; + break; + case INSN_READ: + if(!(s->subdev_flags & SDF_READABLE)) + return -EINVAL; + trig.flags=0; + break; + default: + return -EINVAL; + } + + trig.subdev=insn->subdev; + trig.mode=0; + trig.n_chan=1; + trig.chanlist=&insn->chanspec; + trig.n=1; + + if(s->subdev_flags & SDF_LSAMPL){ + for(i=0;in;i++){ + trig.data=(void *)(data+i); + ret=s->trig[0](dev,s,&trig); + if(ret<0)return ret; + } + }else{ + sampl_t sdata; + + trig.data=&sdata; + for(i=0;in;i++){ + ret=s->trig[0](dev,s,&trig); + if(ret<0)return ret; + data[i]=sdata; + } + } + + return -EINVAL; +} + static int command_trig(comedi_device *dev,comedi_subdevice *s,comedi_trig *it) { int ret; -- 2.26.2