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);
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;
}
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;
}
}
}
- 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;
}
+/*
+ * 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;i<insnlist.n_insns;i++){
+ if(copy_from_user(&insn,insnlist.insns+i,sizeof(comedi_insn))){
+ ret=-EFAULT;
+ break;
+ }
+ if(insn.n>256){
+ 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
/* 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();
}
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
}
void *lock;
void *busy;
+ unsigned int runflags;
int io_bits;
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 *);
#endif
+#define SRF_USER 0x00000001
+#define SRF_RT 0x00000002
+#define SRF_RTIRQ 0x00000004
+
/*
various internal comedi functions
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 *);
#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);
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;
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;
}
}
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;i<insn->n;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;i<insn->n;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;