📄 comedi_fops.c
字号:
switch(insn->insn){ case INSN_GTOD: { struct timeval tv; if(insn->n!=2){ ret=-EINVAL; break; } 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; } udelay(data[0]/1000); ret=1; break; case INSN_INTTRIG: if(insn->n!=1){ ret=-EINVAL; break; } if(insn->subdev>=dev->n_subdevices){ DPRINTK("%d not usable subdevice\n",insn->subdev); ret=-EINVAL; break; } s=dev->subdevices+insn->subdev; if(!s->async){ DPRINTK("no async\n"); ret=-EINVAL; break; } if(!s->async->inttrig){ DPRINTK("no inttrig\n"); ret=-EAGAIN; break; } ret = s->async->inttrig(dev,s,insn->data[0]); if(ret>=0)ret = 1; break; default: DPRINTK("invalid insn\n"); ret=-EINVAL; break; } }else{ /* a subdevice instruction */ if(insn->subdev>=dev->n_subdevices){ DPRINTK("subdevice %d out of range\n",insn->subdev); ret=-EINVAL; goto out; } s=dev->subdevices+insn->subdev; if(s->type==COMEDI_SUBD_UNUSED){ DPRINTK("%d not usable subdevice\n",insn->subdev); ret = -EIO; goto out; } /* 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 out; } if(s->busy){ ret=-EBUSY; goto out; } /* This looks arbitrary. It is. */ s->busy=&parse_insn; 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; } 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; } } 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; } } ret = insn.n;error: if(data)kfree(data); return ret;}/* COMEDI_CMD command ioctl arg: pointer to cmd structure reads: cmd structure at arg channel/range list writes: modified cmd structure at arg*/static int do_cmd_ioctl(comedi_device *dev,void *arg,void *file){ comedi_cmd user_cmd; comedi_subdevice *s; comedi_async *async; 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; } s=dev->subdevices+user_cmd.subdev; async = s->async; if(s->type==COMEDI_SUBD_UNUSED){ DPRINTK("%d not valid subdevice\n",user_cmd.subdev); return -EIO; } if(!s->do_cmd || !s->async){ DPRINTK("subdevice %i does not support commands\n", user_cmd.subdev); return -EIO; } /* are we locked? (ioctl lock) */ if(s->lock && s->lock!=file){ DPRINTK("subdevice locked\n"); return -EACCES; } /* are we busy? */ if(s->busy){ DPRINTK("subdevice busy\n"); return -EBUSY; } s->busy=file; /* 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 = -EINVAL; goto cleanup; } async->cmd=user_cmd; async->cmd.chanlist=NULL; async->cmd.data=NULL; /* load channel/gain list */ /* we should have this already allocated */ async->cmd.chanlist=kmalloc(async->cmd.chanlist_len*sizeof(int),GFP_KERNEL); if(!async->cmd.chanlist){ DPRINTK("allocation failed\n"); ret = -ENOMEM; goto cleanup; } if(copy_from_user(async->cmd.chanlist,user_cmd.chanlist,async->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,async->cmd.chanlist_len,async->cmd.chanlist))<0){ DPRINTK("bad chanlist\n"); goto cleanup; } ret=s->do_cmdtest(dev,s,&async->cmd); if(async->cmd.flags&TRIG_BOGUS || ret){ DPRINTK("test returned %d\n",ret); user_cmd=async->cmd; // 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"); ret = -EFAULT; goto cleanup; } ret = -EAGAIN; goto cleanup; } if(!async->prealloc_bufsz){ ret=-ENOMEM; DPRINTK("no buffer (?)\n"); goto cleanup; } init_async_buf( async ); async->cb_mask = COMEDI_CB_EOA|COMEDI_CB_BLOCK|COMEDI_CB_ERROR; if(async->cmd.flags & TRIG_WAKE_EOS){ async->cb_mask |= COMEDI_CB_EOS; } async->events = 0; s->runflags=SRF_USER; s->subdev_flags|=SDF_RUNNING;#ifdef CONFIG_COMEDI_RT if(async->cmd.flags&TRIG_RT){ comedi_switch_to_rt(dev); s->runflags |= SRF_RT; }#endif ret=s->do_cmd(dev,s); if(ret==0)return 0;cleanup: do_become_nonbusy(dev,s); return ret;}/* COMEDI_CMDTEST command testing ioctl arg: pointer to cmd structure reads: cmd structure at arg channel/range list writes: modified cmd structure at arg*/static int do_cmdtest_ioctl(comedi_device *dev,void *arg,void *file){ comedi_cmd user_cmd; 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; } s=dev->subdevices+user_cmd.subdev; if(s->type==COMEDI_SUBD_UNUSED){ DPRINTK("%d not valid subdevice\n",user_cmd.subdev); return -EIO; } if(!s->do_cmd){ DPRINTK("subdevice %i does not support commands\n", user_cmd.subdev); 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 = -EINVAL; goto cleanup; } /* load channel/gain list */ if(user_cmd.chanlist){ chanlist=kmalloc(user_cmd.chanlist_len*sizeof(int),GFP_KERNEL); if(!chanlist){ DPRINTK("allocation failed\n"); 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"); goto cleanup; } user_cmd.chanlist=chanlist; } 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; goto cleanup; }cleanup: if(chanlist) kfree(chanlist); return ret;}/* COMEDI_LOCK lock subdevice arg: subdevice number reads: none writes: none*/static int do_lock_ioctl(comedi_device *dev,unsigned int arg,void * file){ int ret=0; unsigned long flags; comedi_subdevice *s; if(arg>=dev->n_subdevices) return -EINVAL; s=dev->subdevices+arg; if(s->busy) return -EBUSY; comedi_spin_lock_irqsave(&big_comedi_lock, flags); if(s->lock && s->lock!=file){ ret=-EACCES; }else{ s->lock=file; } comedi_spin_unlock_irqrestore(&big_comedi_lock, flags); if(ret<0) return ret;#if 0 if(s->lock_f) ret=s->lock_f(dev,s);#endif return ret;}/* COMEDI_UNLOCK unlock subdevice arg: subdevice number reads: none writes: none This function isn't protected by the semaphore, since we already own the lock.*/static int do_unlock_ioctl(comedi_device *dev,unsigned int arg,void * file){ comedi_subdevice *s; if(arg>=dev->n_subdevices) return -EINVAL; s=dev->subdevices+arg; if(s->busy) return -EBUSY; if(s->lock && s->lock!=file) return -EACCES; if(s->lock==file){#if 0 if(s->unlock) s->unlock(dev,s);#endif s->lock=NULL; } return 0;}/* COMEDI_CANCEL cancel acquisition ioctl arg: subdevice number reads: nothing writes: nothing*/static int do_cancel_ioctl(comedi_device *dev,unsigned int arg,void *file){ comedi_subdevice *s; if(arg>=dev->n_subdevices) return -EINVAL; s=dev->subdevices+arg; if(s->lock && s->lock!=file) return -EACCES; if(!s->busy) return 0; if(s->busy!=file) return -EBUSY; return do_cancel(dev,s);}/* COMEDI_POLL ioctl instructs driver to synchronize buffers arg: subdevice number reads: nothing writes: nothing*/static int do_poll_ioctl(comedi_device *dev,unsigned int arg,void *file){ comedi_subdevice *s; if(arg>=dev->n_subdevices) return -EINVAL; s=dev->subdevices+arg; if(s->lock && s->lock!=file) return -EACCES; if(!s->busy) return 0; if(s->busy!=file) return -EBUSY; if(s->poll)return s->poll(dev,s); return -EINVAL;}static int do_cancel(comedi_device *dev,comedi_subdevice *s){ int ret=0; if((s->subdev_flags&SDF_RUNNING) && s->cancel) ret=s->cancel(dev,s); do_become_nonbusy(dev,s); return ret;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) /* XXX */#define RDEV_OF_FILE(x) ((x)->f_inode->i_rdev)#else#define RDEV_OF_FILE(x) ((x)->f_dentry->d_inode->i_rdev)#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)void comedi_unmap(struct vm_area_struct *area){ comedi_async *async;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,17) async = (void *)area->vm_pte;#else async = area->vm_private_data;#endif async->mmap_count--;}static struct vm_operations_struct comedi_vm_ops={ close: comedi_unmap,};/* comedi_mmap_v22 */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,17)#define page_address(x) x#endifstatic int comedi_mmap_v22(struct file * file, struct vm_area_struct *vma){ kdev_t minor=MINOR(RDEV_OF_FILE(file)); comedi_device *dev=comedi_get_device_by_minor(minor); comedi_async *async = NULL; unsigned long start = vma->vm_start; unsigned long size; int n_pages; int i; if(!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); return -ENODEV; } if(vma->vm_flags & VM_WRITE){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -