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

📄 comedi_fops.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		async=dev->write_subdev->async;	}else{		async=dev->read_subdev->async;	}	if(async==NULL){		return -EINVAL;	}#if LINUX_VERSION_CODE < 0x020300	if(vma->vm_offset != 0){		DPRINTK("comedi: mmap() offset must be 0.\n");		return -EINVAL;	}#else	if(vma->vm_pgoff != 0){		DPRINTK("comedi: mmap() offset must be 0.\n");		return -EINVAL;	}#endif	size = vma->vm_end - vma->vm_start;	if(size>async->prealloc_bufsz)		return -EFAULT;	if(size&(~PAGE_MASK))		return -EFAULT;	n_pages = size >> PAGE_SHIFT;	for(i=0;i<n_pages;i++){		if(remap_page_range(start, __pa(async->buf_page_list[i]),				PAGE_SIZE, PAGE_SHARED)){			return -EAGAIN;		}		start += PAGE_SIZE;	}	vma->vm_ops = &comedi_vm_ops;#if LINUX_VERSION_CODE < 0x020300	(void *)vma->vm_pte = async;#else	vma->vm_private_data = async;#endif	async->mmap_count++;	return 0;}#endif#if LINUX_VERSION_CODE >= 0x020100static unsigned int comedi_poll_v22(struct file *file, poll_table * wait){	comedi_device *dev;	comedi_subdevice *s;	comedi_async *async;	unsigned int mask;	dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));	if(!dev->attached)	{		DPRINTK("no driver configured on comedi%i\n", dev->minor);		return -ENODEV;	}	poll_wait(file, &dev->read_wait, wait);	poll_wait(file, &dev->write_wait, wait);	mask = 0;	if(dev->read_subdev && dev->read_subdev->async){		s = dev->read_subdev;		async = s->async;		if(!s->busy		   || comedi_buf_read_n_available(async)>0		   || !(s->subdev_flags&SDF_RUNNING)){			mask |= POLLIN | POLLRDNORM;		}	}	if(dev->write_subdev && dev->write_subdev->async){		s = dev->write_subdev;		async = s->async;		if(!s->busy		   || !(s->subdev_flags&SDF_RUNNING)		   || comedi_buf_write_n_available(async)>0){			mask |= POLLOUT | POLLWRNORM;		}	}	return mask;}#endifstatic ssize_t comedi_write_v22(struct file *file,const char *buf,size_t nbytes,loff_t *offset){	comedi_device *dev;	comedi_subdevice *s;	comedi_async *async;	int n,m,count=0,retval=0;	DECLARE_WAITQUEUE(wait,current);	dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));	if(!dev->attached)	{		DPRINTK("no driver configured on comedi%i\n", dev->minor);		return -ENODEV;	}	if(dev->write_subdev == NULL)return -EIO;	s = dev->write_subdev;	async = s->async;	if(!nbytes)return 0;	if(!s->busy)		return 0;	if(s->busy != file)		return -EACCES;	add_wait_queue(&dev->write_wait,&wait);	while(nbytes>0 && !retval){		current->state=TASK_INTERRUPTIBLE;		n=nbytes;		m = n;		if(async->buf_write_ptr + m > async->prealloc_bufsz){			m = async->prealloc_bufsz - async->buf_write_ptr;		}		m = comedi_buf_write_alloc(async, m);		if(m < n) n = m;		if(n==0){			if(file->f_flags&O_NONBLOCK){				retval=-EAGAIN;				break;			}			if(signal_pending(current)){				retval=-ERESTARTSYS;				break;			}			if(!(s->subdev_flags&SDF_RUNNING)){				if(s->runflags & SRF_ERROR){					retval = -EPIPE;				}else{					retval = 0;				}				do_become_nonbusy(dev,s);				break;			}			schedule();			continue;		}		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,			buf, n);		if(m){			n -= m;			retval = -EFAULT;		}		comedi_buf_munge(dev, s, n);		comedi_buf_write_free(async, n);		count+=n;		nbytes-=n;		buf+=n;		break;	/* makes device work like a pipe */	}	current->state=TASK_RUNNING;	remove_wait_queue(&dev->write_wait,&wait);	return (count ? count : retval);}static ssize_t comedi_read_v22(struct file * file,char *buf,size_t nbytes,loff_t *offset){	comedi_device *dev;	comedi_subdevice *s;	comedi_async *async;	int n,m,count=0,retval=0;	DECLARE_WAITQUEUE(wait,current);	dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));	if(!dev->attached)	{		DPRINTK("no driver configured on comedi%i\n", dev->minor);		return -ENODEV;	}	s = dev->read_subdev;	if(s == NULL)return -EIO;	async = s->async;	if(!nbytes)return 0;	if(!s->busy)		return 0;	if(s->busy != file)		return -EACCES;	add_wait_queue(&dev->read_wait,&wait);	while(nbytes>0 && !retval){		current->state=TASK_INTERRUPTIBLE;		n=nbytes;		m = comedi_buf_read_n_available(async);//printk("%d available\n",m);		if(async->buf_read_ptr + m > async->prealloc_bufsz){			m = async->prealloc_bufsz - async->buf_read_ptr;		}//printk("%d contiguous\n",m);		if(m<n)n=m;		if(n==0){			if(!(s->subdev_flags&SDF_RUNNING)){				do_become_nonbusy(dev,s);				if(s->runflags & SRF_ERROR){					retval = -EPIPE;				}else{					retval = 0;				}				break;			}			if(file->f_flags&O_NONBLOCK){				retval=-EAGAIN;				break;			}			if(signal_pending(current)){				retval=-ERESTARTSYS;				break;			}			schedule();			continue;		}		m = copy_to_user(buf, async->prealloc_buf +			async->buf_read_ptr, n);		if(m){			n -= m;			retval = -EFAULT;		}		comedi_buf_read_free(async, n);		count+=n;		nbytes-=n;		buf+=n;		break;	/* makes device work like a pipe */	}	if(!(s->subdev_flags&SDF_RUNNING) &&		!(s->runflags & SRF_ERROR) &&		async->buf_read_count - async->buf_write_count == 0)	{		do_become_nonbusy(dev,s);	}	current->state=TASK_RUNNING;	remove_wait_queue(&dev->read_wait,&wait);	return (count ? count : retval);}/*   This function restores a subdevice to an idle state. */void do_become_nonbusy(comedi_device *dev,comedi_subdevice *s){	comedi_async *async = s->async;	/* we do this because it's useful for the non-standard cases */	s->subdev_flags &= ~SDF_RUNNING;#ifdef CONFIG_COMEDI_RT	if(s->runflags&SRF_RT){		comedi_switch_to_non_rt(dev);		s->runflags &= ~SRF_RT;	}#endif	if(async){		init_async_buf( async );	}else{		printk("BUG: (?) do_become_nonbusy called with async=0\n");	}	s->busy=NULL;}/* no chance that these will change soon */#define SEEK_SET 0#define SEEK_CUR 1#define SEEK_END 2static loff_t comedi_lseek_v22(struct file *file,loff_t offset,int origin){	comedi_device *dev;	loff_t new_offset;	dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));	switch(origin){	case SEEK_SET:		new_offset = offset;		break;	case SEEK_CUR:		new_offset = file->f_pos + offset;		break;	case SEEK_END:		new_offset = dev->n_subdevices + offset;		break;	default:		return -EINVAL;	}	if(new_offset<0 || new_offset >= dev->n_subdevices)		return -EINVAL;	return file->f_pos=new_offset;}static int comedi_fop_open(struct inode *inode,struct file *file){	kdev_t minor=MINOR(inode->i_rdev);	comedi_device *dev;	char mod[32];	if(minor>=COMEDI_NDEVICES)return -ENODEV;	dev=comedi_get_device_by_minor(minor);	/* This is slightly hacky, but we want module autoloading	 * to work for root. 	 * case: user opens device, attached -> ok	 * case: user opens device, unattached, in_request_module=0 -> autoload	 * case: user opens device, unattached, in_request_module=1 -> fail	 * case: root opens device, attached -> ok	 * case: root opens device, unattached, in_request_module=1 -> ok	 *   (typically called from modprobe)	 * case: root opens device, unattached, in_request_module=0 -> autoload	 *	 * The last could be changed to "-> ok", which would deny root	 * autoloading.	 */	if(dev->attached)		goto ok;	if(!suser() && dev->in_request_module)		return -ENODEV;	if(suser() && dev->in_request_module)		goto ok;	dev->in_request_module=1;	sprintf(mod,"char-major-%i-%i",COMEDI_MAJOR,minor);#ifdef CONFIG_KMOD	request_module(mod);#endif	dev->in_request_module=0;	if(dev->attached || suser())		goto ok;	return -ENODEV;ok:	MOD_INC_USE_COUNT;	if(dev->attached && dev->driver->module){		__MOD_INC_USE_COUNT(dev->driver->module);	}	if(dev->attached && dev->use_count==0 && dev->open){		dev->open(dev);	}	dev->use_count++;	return 0;}static int comedi_close_v22(struct inode *inode,struct file *file){	comedi_device *dev=comedi_get_device_by_minor(MINOR(inode->i_rdev));	comedi_subdevice *s = NULL;	int i;	for(i=0;i<dev->n_subdevices;i++){		s=dev->subdevices+i;		if(s->busy==file){			do_cancel(dev,s);		}		if(s->lock==file){			s->lock=NULL;		}	}	if(dev->attached && dev->use_count==1 && dev->close){		dev->close(dev);	}	MOD_DEC_USE_COUNT;	if(dev->attached && dev->driver->module){		__MOD_DEC_USE_COUNT(dev->driver->module);	}	dev->use_count--;#if LINUX_VERSION_CODE >= 0x020100	if(file->f_flags & FASYNC){		comedi_fasync(-1,file,0);	}#endif	return 0;}#if LINUX_VERSION_CODE >= 0x020100static int comedi_fasync (int fd, struct file *file, int on){	comedi_device *dev=comedi_get_device_by_minor(MINOR(RDEV_OF_FILE(file)));	return fasync_helper(fd,file,on,&dev->async_queue);}#endif/*	kernel compatibility*/#if LINUX_VERSION_CODE < 0x020100static int comedi_write_v20(struct inode *inode,struct file *file,const char *buf,int nbytes){	return comedi_write_v22(file,buf,nbytes,NULL);}static int comedi_read_v20(struct inode *inode,struct file *file,char *buf,int nbytes){	return comedi_read_v22(file,buf,nbytes,NULL);}static int comedi_lseek_v20(struct inode * inode,struct file *file,off_t offset,int origin){	return comedi_lseek_v22(file,offset,origin);}static void comedi_close_v20(struct inode *inode,struct file *file){	comedi_close_v22(inode,file);}#define comedi_ioctl_v20 comedi_ioctl#define comedi_open_v20 comedi_fop_openstatic struct file_operations comedi_fops={	lseek		: comedi_lseek_v20,	ioctl		: comedi_ioctl_v20,	open		: comedi_open_v20,	release		: comedi_close_v20,	read		: comedi_read_v20,	write		: comedi_write_v20,};#endif#if LINUX_VERSION_CODE >= 0x020200#define comedi_ioctl_v22 comedi_ioctl#define comedi_open_v22 comedi_fop_openstatic struct file_operations comedi_fops={#if LINUX_VERSION_CODE >= 0x020400	owner		: THIS_MODULE,#endif	llseek		: comedi_lseek_v22,	ioctl		: comedi_ioctl_v22,	open		: comedi_open_v22,	release		: comedi_close_v22,	read		: comedi_read_v22,	write		: comedi_write_v22,	mmap		: comedi_mmap_v22,	poll		: comedi_poll_v22,	fasync		: comedi_fasync,};#endifstatic int __init comedi_init(void){	int i;	printk("comedi: version " COMEDI_RELEASE " - David Schleef <ds@schleef.org>\n");	if(devfs_register_chrdev(COMEDI_MAJOR,"comedi",&comedi_fops)){		printk("comedi: unable to get major %d\n",COMEDI_MAJOR);		return -EIO;	}	comedi_devices=(comedi_device *)kmalloc(sizeof(comedi_device)*COMEDI_NDEVICES,GFP_KERNEL);	if(!comedi_devices)		return -ENOMEM;	memset(comedi_devices,0,sizeof(comedi_device)*COMEDI_NDEVICES);	for(i=0;i<COMEDI_NDEVICES;i++){		comedi_devices[i].minor=i;		spin_lock_init(&(comedi_devices[i].spinlock));	}	/* XXX requires /proc interface */	comedi_proc_init();	for(i=0;i<COMEDI_NDEVICES;i++){		char name[20];		sprintf(name, "comedi%d", i);		devfs_register(NULL, name, DEVFS_FL_DEFAULT,			COMEDI_MAJOR, i, 0666 | S_IFCHR, &comedi_fops, NULL);	}		comedi_rt_init();	return 0;}static void __exit comedi_cleanup(void){	int i;	if(MOD_IN_USE)		printk("comedi: module in use -- remove delayed\n");	for(i=0;i<4;i++){		char name[20];		sprintf(name, "comedi%d", i);		devfs_unregister(devfs_find_handle(NULL, name,			COMEDI_MAJOR, i, DEVFS_SPECIAL_CHR, 0));	}	devfs_unregister_chrdev(COMEDI_MAJOR,"comedi");	comedi_proc_cleanup();	for(i=0;i<COMEDI_NDEVICES;i++){		comedi_device *dev;		dev=comedi_get_device_by_minor(i);		if(dev->attached)			comedi_device_detach(dev);	}	kfree(comedi_devices);	comedi_rt_cleanup();}module_init(comedi_init);module_exit(comedi_cleanup);void comedi_error(const comedi_device *dev,const char *s){	rt_printk("comedi%d: %s: %s\n",dev->minor,dev->driver->driver_name,s);}void comedi_event(comedi_device *dev,comedi_subdevice *s, unsigned int mask){	comedi_async *async = s->async;	mask = s->async->events;	s->async->events = 0;	mask |= COMEDI_CB_BLOCK;	//DPRINTK("comedi_event %x\n",mask);	if( (s->subdev_flags & SDF_RUNNING) == 0)		return;	if(mask&(COMEDI_CB_EOA|COMEDI_CB_ERROR|COMEDI_CB_OVERFLOW)){		s->subdev_flags &= ~SDF_RUNNING;	}	/* remember if an error event has occured, so an error	 * can be returned the next time the user does a read() */	if(mask & (COMEDI_CB_ERROR|COMEDI_CB_OVERFLOW)){		s->runflags |= SRF_ERROR;	}	if(async->cb_mask&mask){		if(s->runflags&SRF_USER){			if(dev->rt){#ifdef CONFIG_COMEDI_RT				// pend wake up				if(s==dev->read_subdev)					comedi_rt_pend_wakeup(&dev->read_wait);				if(s==dev->write_subdev)					comedi_rt_pend_wakeup(&dev->write_wait);#else				printk("BUG: comedi_event() code unreachable\n");#endif			}else{				if(s==dev->read_subdev){					wake_up_interruptible(&dev->read_wait);					KILL_FASYNC(dev->async_queue, SIGIO, POLL_IN);				}				if(s==dev->write_subdev){					wake_up_interruptible(&dev->write_wait);					KILL_FASYNC(dev->async_queue, SIGIO, POLL_OUT);				}			}		}else{			if(async->cb_func)async->cb_func(mask,async->cb_arg);			/* XXX bug here.  If subdevice A is rt, and			 * subdevice B tries to callback to a normal			 * linux kernel function, it will be at the			 * wrong priority.  Since this isn't very			 * common, I'm not going to worry about it. */		}	}}static void init_async_buf( comedi_async *async ){	async->buf_write_alloc_count = 0;	async->buf_write_count = 0;	async->buf_read_count = 0;	async->buf_write_ptr = 0;	async->buf_read_ptr = 0;	async->cur_chan = 0;	async->scan_progress = 0;	async->munge_chan = 0;}

⌨️ 快捷键说明

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