⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comedi_fops.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    comedi/comedi_fops.c    comedi kernel module    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#undef DEBUG#define __NO_VERSION__#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/fcntl.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/devfs_fs_kernel.h>#include <linux/vmalloc.h>#include <linux/comedidev.h>#include <asm/io.h>#include <asm/uaccess.h>//#include "kvmem.h"MODULE_AUTHOR("David Schleef <ds@schleef.org>");MODULE_DESCRIPTION("Comedi core module");MODULE_LICENSE("GPL");#ifndef KILL_FASYNC#define KILL_FASYNC(a,b,c) kill_fasync(&(a),(b),(c))#endif#ifdef CONFIG_COMEDI_DEBUGint comedi_debug;MODULE_PARM(comedi_debug, "i");#endifcomedi_device *comedi_devices;spinlock_t big_comedi_lock = SPIN_LOCK_UNLOCKED;static int do_devconfig_ioctl(comedi_device *dev,comedi_devconfig *arg,kdev_t minor);static int do_bufconfig_ioctl(comedi_device *dev,void *arg);static int do_devinfo_ioctl(comedi_device *dev,comedi_devinfo *arg);static int do_subdinfo_ioctl(comedi_device *dev,comedi_subdinfo *arg,void *file);static int do_chaninfo_ioctl(comedi_device *dev,comedi_chaninfo *arg);static int do_bufinfo_ioctl(comedi_device *dev,void *arg);static int do_cmd_ioctl(comedi_device *dev,void *arg,void *file);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 int do_insn_ioctl(comedi_device *dev,void *arg,void *file);static int do_poll_ioctl(comedi_device *dev,unsigned int subd,void *file);void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s);static int do_cancel(comedi_device *dev,comedi_subdevice *s);#if LINUX_VERSION_CODE >= 0x020100static int comedi_fasync (int fd, struct file *file, int on);#endifstatic void init_async_buf( comedi_async *async );static int comedi_ioctl(struct inode * inode,struct file * file,	unsigned int cmd,unsigned long arg){	kdev_t minor=MINOR(inode->i_rdev);	comedi_device *dev=comedi_get_device_by_minor(minor);	/* Device config is special, because it must work on	 * an unconfigured device. */	if(cmd==COMEDI_DEVCONFIG){		return do_devconfig_ioctl(dev,(void *)arg,minor);	}	if(!dev->attached){		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);		return -ENODEV;	}	switch(cmd)	{	case COMEDI_BUFCONFIG:		return do_bufconfig_ioctl(dev,(void*)arg);	case COMEDI_DEVINFO:		return do_devinfo_ioctl(dev,(void *)arg);	case COMEDI_SUBDINFO:		return do_subdinfo_ioctl(dev,(void *)arg,file);	case COMEDI_CHANINFO:		return do_chaninfo_ioctl(dev,(void *)arg);	case COMEDI_RANGEINFO:		return do_rangeinfo_ioctl(dev,(void *)arg);	case COMEDI_BUFINFO:		return do_bufinfo_ioctl(dev,(void*)arg);	case COMEDI_LOCK:		return do_lock_ioctl(dev,arg,file);	case COMEDI_UNLOCK:		return do_unlock_ioctl(dev,arg,file);	case COMEDI_CANCEL:		return do_cancel_ioctl(dev,arg,file);	case COMEDI_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);	case COMEDI_INSN:		return do_insn_ioctl(dev,(void *)arg,file);	case COMEDI_POLL:		return do_poll_ioctl(dev,arg,file);	default:		return -ENOTTY;	}}/*	COMEDI_DEVCONFIG	device config ioctl	arg:		pointer to devconfig structure	reads:		devconfig structure at arg	writes:		none*/static int do_devconfig_ioctl(comedi_device *dev,comedi_devconfig *arg,kdev_t minor){	comedi_devconfig it;	int ret;	unsigned char *aux_data = NULL;	int aux_len;	if(!suser())		return -EPERM;	if(arg==NULL){		return comedi_device_detach(dev);	}	if(copy_from_user(&it,arg,sizeof(comedi_devconfig)))		return -EFAULT;	it.board_name[COMEDI_NAMELEN-1]=0;	if(it.options[COMEDI_DEVCONF_AUX_DATA] &&	   it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]){		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];		if(aux_len<0)return -EFAULT;		aux_data = kmalloc(aux_len, GFP_KERNEL);		if(!aux_data)return -EFAULT;		if(copy_from_user(aux_data,		    (void *)it.options[COMEDI_DEVCONF_AUX_DATA], aux_len)){			kfree(aux_data);			return -EFAULT;		}		it.options[COMEDI_DEVCONF_AUX_DATA] = (unsigned long)aux_data;	}	ret = comedi_device_attach(dev,&it);	if(aux_data) kfree(aux_data);	return ret;}/*	COMEDI_BUFCONFIG	buffer configuration ioctl	arg:		pointer to bufconfig structure	reads:		bufconfig at arg	writes:		modified bufconfig at arg*/static int do_bufconfig_ioctl(comedi_device *dev,void *arg){	comedi_bufconfig bc;	comedi_async *async;	comedi_subdevice *s;	int ret = 0;	if(copy_from_user(&bc,arg,sizeof(comedi_bufconfig)))		return -EFAULT;	if(bc.subdevice>=dev->n_subdevices || bc.subdevice<0)		return -EINVAL;	s=dev->subdevices+bc.subdevice;	async=s->async;	if(!async){		DPRINTK("subdevice does not have async capability\n");		bc.size = 0;		bc.maximum_size = 0;		goto copyback;	}	if(bc.maximum_size){		if(!suser())return -EPERM;		async->max_bufsize = bc.maximum_size;	}	if(bc.size){		if(bc.size > async->max_bufsize)			return -EPERM;		if(s->busy)return -EBUSY;		if(async->mmap_count){			DPRINTK("subdevice is mmapped, cannot resize buffer\n");			return -EBUSY;		}		if(!async->prealloc_buf)			return -EINVAL;		/* make sure buffer is an integral number of pages		 * (we round up) */		bc.size = (bc.size + 1)&PAGE_MASK;		ret = comedi_buf_alloc(dev, s, bc.size);		if(ret < 0) return ret;		if(s->buf_change){			ret = s->buf_change(dev,s,bc.size);			if(ret < 0) return ret;		}		DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",			dev->minor, bc.subdevice, async->prealloc_bufsz);	}	bc.size = async->prealloc_bufsz;	bc.maximum_size = async->max_bufsize;copyback:	if(copy_to_user(arg,&bc,sizeof(comedi_bufconfig)))		return -EFAULT;	return 0;}/*	COMEDI_DEVINFO	device info ioctl	arg:		pointer to devinfo structure	reads:		none	writes:		devinfo structure*/static int do_devinfo_ioctl(comedi_device *dev,comedi_devinfo *arg){	comedi_devinfo devinfo;	memset(&devinfo,0,sizeof(devinfo));	/* fill devinfo structure */	devinfo.version_code=COMEDI_VERSION_CODE;	devinfo.n_subdevs=dev->n_subdevices;	memcpy(devinfo.driver_name,dev->driver->driver_name,COMEDI_NAMELEN);	memcpy(devinfo.board_name,dev->board_name,COMEDI_NAMELEN);	if(dev->read_subdev){		devinfo.read_subdevice = dev->read_subdev - dev->subdevices;	}else{		devinfo.read_subdevice = -1;	}	if(dev->write_subdev){		devinfo.write_subdevice = dev->write_subdev - dev->subdevices;	}else{		devinfo.write_subdevice = -1;	}	if(copy_to_user(arg,&devinfo,sizeof(comedi_devinfo)))		return -EFAULT;	return 0;}/*	COMEDI_SUBDINFO	subdevice info ioctl		arg:		pointer to array of subdevice info structures		reads:		none		writes:		array of subdevice info structures at arg		*/static int do_subdinfo_ioctl(comedi_device *dev,comedi_subdinfo *arg,void *file){	int ret,i;	comedi_subdinfo *tmp,*us;	comedi_subdevice *s;	tmp=kmalloc(dev->n_subdevices*sizeof(comedi_subdinfo),GFP_KERNEL);	if(!tmp)		return -ENOMEM;	memset(tmp,0,sizeof(comedi_subdinfo)*dev->n_subdevices);	/* fill subdinfo structs */	for(i=0;i<dev->n_subdevices;i++){		s=dev->subdevices+i;		us=tmp+i;		us->type		= s->type;		us->n_chan		= s->n_chan;		us->subd_flags		= s->subdev_flags;#define TIMER_nanosec 5	/* backwards compatibility */		us->timer_type		= TIMER_nanosec;		us->len_chanlist	= s->len_chanlist;		us->maxdata		= s->maxdata;		if(s->range_table){			us->range_type	= (dev->minor<<28)|(i<<24)|(0<<16)|					(s->range_table->length);		}else{			us->range_type	= 0; /* XXX */		}		us->flags		= s->flags;				if(s->busy)			us->subd_flags |= SDF_BUSY;		if(s->busy == file)			us->subd_flags |= SDF_BUSY_OWNER;		if(s->lock)			us->subd_flags |= SDF_LOCKED;		if(s->lock == file)			us->subd_flags |= SDF_LOCK_OWNER;		if(!s->maxdata && s->maxdata_list)			us->subd_flags |= SDF_MAXDATA;		if(s->flaglist)			us->subd_flags |= SDF_FLAGS;		if(s->range_table_list)			us->subd_flags |= SDF_RANGETYPE;		if(s->do_cmd)			us->subd_flags |= SDF_CMD;		us->settling_time_0 = s->settling_time_0;	}		ret=copy_to_user(arg,tmp,dev->n_subdevices*sizeof(comedi_subdinfo));		kfree(tmp);	return ret?-EFAULT:0;}/*	COMEDI_CHANINFO	subdevice info ioctl		arg:		pointer to chaninfo structure		reads:		chaninfo structure at arg	writes:		arrays at elements of chaninfo structure*/static int do_chaninfo_ioctl(comedi_device *dev,comedi_chaninfo *arg){	comedi_subdevice *s;	comedi_chaninfo it;	if(copy_from_user(&it,arg,sizeof(comedi_chaninfo)))		return -EFAULT;	if(it.subdev>=dev->n_subdevices)		return -EINVAL;	s=dev->subdevices+it.subdev;	if(it.maxdata_list){		if(s->maxdata || !s->maxdata_list)			return -EINVAL;		if(copy_to_user(it.maxdata_list,s->maxdata_list,s->n_chan*sizeof(lsampl_t)))			return -EFAULT;	}	if(it.flaglist){		if(!s->flaglist)return -EINVAL;		if(copy_to_user(it.flaglist,s->flaglist,s->n_chan*sizeof(unsigned int)))			return -EFAULT;	}				if(it.rangelist){		int i;		if(!s->range_table_list)return -EINVAL;		for(i=0;i<s->n_chan;i++){			int x;			x=(dev->minor<<28)|(it.subdev<<24)|(i<<16)|				(s->range_table_list[i]->length);			put_user(x,it.rangelist+i);		}		//if(copy_to_user(it.rangelist,s->range_type_list,s->n_chan*sizeof(unsigned int)))		//	return -EFAULT;	}	return 0;} /*	COMEDI_BUFINFO	buffer information ioctl	arg:		pointer to bufinfo structure	reads:		bufinfo at arg	writes:		modified bufinfo at arg*/static int do_bufinfo_ioctl(comedi_device *dev,void *arg){	comedi_bufinfo bi;	comedi_subdevice *s;	comedi_async *async;	if(copy_from_user(&bi,arg, sizeof(comedi_bufinfo)))		return -EFAULT;	if(bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)		return -EINVAL;	s=dev->subdevices + bi.subdevice;	async=s->async;	if(s!=dev->read_subdev && s!=dev->write_subdev)return -EINVAL;	if(!async){		DPRINTK("subdevice does not have async capability\n");		bi.buf_int_ptr = 0;		bi.buf_user_ptr = 0;		bi.buf_int_count = 0;		bi.buf_user_count = 0;		goto copyback;	}	if(bi.bytes_read && s==dev->read_subdev){		comedi_buf_read_free(async, bi.bytes_read);		if(!(s->subdev_flags&SDF_RUNNING) &&		   !(s->runflags & SRF_ERROR) &&		   async->buf_write_count==async->buf_read_count){			do_become_nonbusy(dev,s);		}	}	if(bi.bytes_written && s==dev->write_subdev){		bi.bytes_written = comedi_buf_write_alloc( async, bi.bytes_written );		comedi_buf_munge(dev, s, bi.bytes_written);		comedi_buf_write_free(async, bi.bytes_written);	}	if(s==dev->read_subdev){		bi.buf_int_count = async->buf_write_count;		bi.buf_int_ptr = async->buf_write_ptr;		bi.buf_user_count = async->buf_read_count;		bi.buf_user_ptr = async->buf_read_ptr;	}else{		bi.buf_int_count = async->buf_read_count;		bi.buf_int_ptr = async->buf_read_ptr;		bi.buf_user_count = async->buf_write_count;		bi.buf_user_ptr = async->buf_write_ptr;	}copyback:	if(copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))		return -EFAULT;	return 0;}static int parse_insn(comedi_device *dev,comedi_insn *insn,lsampl_t *data,void *file);/* * 	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) *//* arbitrary limits */#define MAX_SAMPLES 256#define MAX_INSNS 10static int do_insnlist_ioctl(comedi_device *dev,void *arg,void *file){	comedi_insnlist insnlist;	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>=MAX_INSNS){		DPRINTK("insnlist too long\n");		return -EINVAL;	}	data=kmalloc(sizeof(lsampl_t)*MAX_SAMPLES,GFP_KERNEL);	if(!data){		DPRINTK("kmalloc failed\n");		ret = -ENOMEM;		goto error;	}	insns=kmalloc(sizeof(comedi_insn)*insnlist.n_insns,GFP_KERNEL);	if(!insns){		DPRINTK("kmalloc failed\n");		ret = -ENOMEM;		goto error;	}	if(copy_from_user(insns,insnlist.insns,sizeof(comedi_insn)*insnlist.n_insns)){		DPRINTK("copy_from_user failed\n");		ret=-EFAULT;		goto error;	}	for(i=0;i<insnlist.n_insns;i++){		if(insns[i].n>MAX_SAMPLES){			DPRINTK("number of samples too large\n");			ret=-EINVAL;			goto error;		}		if(insns[i].insn&INSN_MASK_WRITE){			if(copy_from_user(data,insns[i].data,					insns[i].n*sizeof(lsampl_t))){				DPRINTK("copy_from_user failed\n");				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(insns[i].insn&INSN_MASK_READ){			if(copy_to_user(insns[i].data,data,					insns[i].n*sizeof(lsampl_t))){				DPRINTK("copy_to_user failed\n");				ret=-EFAULT;				goto error;			}		}	}error:	if(insns)kfree(insns);	if(data)kfree(data);	if(ret<0)return ret;	return i;}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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -