/*
COMEDI_CMD
command ioctl
-
+
arg:
pointer to cmd structure
-
+
reads:
cmd structure at arg
channel/range list
-
+
writes:
modified cmd structure at arg
comedi_cmd user_cmd;
comedi_subdevice *s;
int ret=0;
-
+ unsigned int *chanlist_saver=NULL;
+
if(copy_from_user(&user_cmd,arg,sizeof(comedi_cmd))){
DPRINTK("bad cmd address\n");
return -EFAULT;
}
-
+
+ // save user's chanlist pointer so it can be restored later
+ chanlist_saver = user_cmd.chanlist;
+
if(user_cmd.subdev>=dev->n_subdevices){
DPRINTK("%d no such subdevice\n",user_cmd.subdev);
return -ENODEV;
DPRINTK("%d not valid subdevice\n",user_cmd.subdev);
return -EIO;
}
-
+
if(!s->do_cmd){
DPRINTK("subdevice does not support commands\n");
return -EIO;
}
-
+
/* are we locked? (ioctl lock) */
if(s->lock && s->lock!=file){
DPRINTK("subdevice locked\n");
ret = -ENOMEM;
goto cleanup;
}
-
+
if(copy_from_user(s->cmd.chanlist,user_cmd.chanlist,s->cmd.chanlist_len*sizeof(int))){
DPRINTK("fault reading chanlist\n");
ret = -EFAULT;
goto cleanup;
}
-
+
/* make sure each element in channel/gain list is valid */
if((ret=check_chanlist(s,s->cmd.chanlist_len,s->cmd.chanlist))<0){
DPRINTK("bad chanlist\n");
goto cleanup;
}
-
+
ret=s->do_cmdtest(dev,s,&s->cmd);
if(s->cmd.flags&TRIG_BOGUS || ret){
DPRINTK("test returned %d\n",ret);
user_cmd=s->cmd;
- user_cmd.chanlist = NULL;
+ // restore chanlist pointer before copying back
+ user_cmd.chanlist = chanlist_saver;
user_cmd.data = NULL;
if(copy_to_user(arg,&user_cmd,sizeof(comedi_cmd))){
DPRINTK("fault writing cmd\n");
s->cur_chan = 0;
s->cur_chanlist_len = s->cmd.chanlist_len;
-
+
s->cb_mask = COMEDI_CB_EOA|COMEDI_CB_BLOCK|COMEDI_CB_ERROR;
if(s->cmd.flags & TRIG_WAKE_EOS){
s->cb_mask |= COMEDI_CB_EOS;
#endif
ret=s->do_cmd(dev,s);
-
+
if(ret==0)return 0;
cleanup:
do_become_nonbusy(dev,s);
-
+
return ret;
}
comedi_subdevice *s;
int ret=0;
unsigned int *chanlist=NULL;
-
+ unsigned int *chanlist_saver=NULL;
+
if(copy_from_user(&user_cmd,arg,sizeof(comedi_cmd))){
DPRINTK("bad cmd address\n");
return -EFAULT;
}
-
+
+ // save user's chanlist pointer so it can be restored later
+ chanlist_saver = user_cmd.chanlist;
+
if(user_cmd.subdev>=dev->n_subdevices){
DPRINTK("%d no such subdevice\n",user_cmd.subdev);
return -ENODEV;
DPRINTK("%d not valid subdevice\n",user_cmd.subdev);
return -EIO;
}
-
+
if(!s->do_cmd){
DPRINTK("subdevice does not support commands\n");
return -EIO;
}
-
+
/* make sure channel/gain list isn't too long */
if(user_cmd.chanlist_len > s->len_chanlist){
DPRINTK("channel/gain list too long %d > %d\n",user_cmd.chanlist_len,s->len_chanlist);
ret = -ENOMEM;
goto cleanup;
}
-
+
if(copy_from_user(chanlist,user_cmd.chanlist,user_cmd.chanlist_len*sizeof(int))){
DPRINTK("fault reading chanlist\n");
ret = -EFAULT;
goto cleanup;
}
-
+
/* make sure each element in channel/gain list is valid */
if((ret=check_chanlist(s,user_cmd.chanlist_len,chanlist))<0){
DPRINTK("bad chanlist\n");
}
ret=s->do_cmdtest(dev,s,&user_cmd);
-
+
+ // restore chanlist pointer before copying back
+ user_cmd.chanlist = chanlist_saver;
+
if(copy_to_user(arg,&user_cmd,sizeof(comedi_cmd))){
DPRINTK("bad cmd address\n");
ret=-EFAULT;
cleanup:
if(chanlist)
kfree(chanlist);
-
+
return ret;
}