comedi_fops.c revision 1dd33ab8a9397793d65b9fc090174ff7cdfaff95
1ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
2ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    comedi/comedi_fops.c
3ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    comedi kernel module
4ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI - Linux Control and Measurement Device Interface
6ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
8ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    This program is free software; you can redistribute it and/or modify
9ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    it under the terms of the GNU General Public License as published by
10ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    the Free Software Foundation; either version 2 of the License, or
11ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    (at your option) any later version.
12ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
13ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    This program is distributed in the hope that it will be useful,
14ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    but WITHOUT ANY WARRANTY; without even the implied warranty of
15ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    GNU General Public License for more details.
17ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
18ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    You should have received a copy of the GNU General Public License
19ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    along with this program; if not, write to the Free Software
20ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
22ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
23ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
24ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#undef DEBUG
25ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
26ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define __NO_VERSION__
27ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include "comedi_fops.h"
28ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include "comedi_compat32.h"
29ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
30ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/module.h>
31ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/errno.h>
32ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/kernel.h>
33ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/sched.h>
34ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/fcntl.h>
35ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/delay.h>
36ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/ioport.h>
37ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/mm.h>
38ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/slab.h>
39ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/kmod.h>
40ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/poll.h>
41ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/init.h>
42ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/device.h>
43ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/vmalloc.h>
44ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/fs.h>
45ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include "comedidev.h"
46ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/cdev.h>
47ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
48476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/io.h>
49476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/uaccess.h>
50ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
51476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman/* #include "kvmem.h" */
52ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
53ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_AUTHOR("http://www.comedi.org");
54ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_DESCRIPTION("Comedi core module");
55ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_LICENSE("GPL");
56ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
57ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_DEBUG
58ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_debug;
59ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_param(comedi_debug, int, 0644);
60ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
61ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
626a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottint comedi_autoconfig = 1;
636a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottmodule_param(comedi_autoconfig, bool, 0444);
646a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbott
651dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrint comedi_num_legacy_minors = 0;
661dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrmodule_param(comedi_num_legacy_minors, int, 0444);
671dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr
68ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic DEFINE_SPINLOCK(comedi_file_info_table_lock);
69476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic struct comedi_device_file_info
70476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman    *comedi_file_info_table[COMEDI_NUM_MINORS];
71476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
72476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg);
73476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_bufconfig_ioctl(comedi_device *dev, void *arg);
74476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
75476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    struct file *file);
76476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
77476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			     void *file);
78476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg);
79476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_bufinfo_ioctl(comedi_device *dev, void *arg);
80476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cmd_ioctl(comedi_device *dev, void *arg, void *file);
81476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file);
82476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file);
83476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file);
84476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file);
85476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file);
86476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_insn_ioctl(comedi_device *dev, void *arg, void *file);
87476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_poll_ioctl(comedi_device *dev, unsigned int subd, void *file);
88476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
89476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanextern void do_become_nonbusy(comedi_device *dev, comedi_subdevice *s);
90476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cancel(comedi_device *dev, comedi_subdevice *s);
91ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
92ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on);
93ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
94476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int is_device_busy(comedi_device *dev);
95ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
96ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_UNLOCKED_IOCTL
97ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
98476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				  unsigned long arg)
99ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_ioctl(struct inode *inode, struct file *file,
101476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			unsigned int cmd, unsigned long arg)
102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
105476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
106476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int rc;
109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* Device config is special, because it must work on
113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * an unconfigured device. */
114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cmd == COMEDI_DEVCONFIG) {
115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devconfig_ioctl(dev, (void *)arg);
116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENODEV;
122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (cmd) {
126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFCONFIG:
127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufconfig_ioctl(dev, (void *)arg);
128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_DEVINFO:
130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devinfo_ioctl(dev, (void *)arg, file);
131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_SUBDINFO:
133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_subdinfo_ioctl(dev, (void *)arg, file);
134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CHANINFO:
136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_chaninfo_ioctl(dev, (void *)arg);
137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_RANGEINFO:
139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_rangeinfo_ioctl(dev, (void *)arg);
140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFINFO:
142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufinfo_ioctl(dev, (void *)arg);
143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmd_ioctl(dev, (void *)arg, file);
155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmdtest_ioctl(dev, (void *)arg, file);
158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insnlist_ioctl(dev, (void *)arg, file);
161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insn_ioctl(dev, (void *)arg, file);
164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
173476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
191476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg)
192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_devconfig it;
194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
204476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&it, arg, sizeof(comedi_devconfig)))
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
218476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
229476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
234476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
238476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
244476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
245476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
271476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_bufconfig_ioctl(comedi_device *dev, void *arg)
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_bufconfig bc;
274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async;
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&bc, arg, sizeof(comedi_bufconfig)))
279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (bc.size > async->max_bufsize)
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice is busy, cannot resize buffer\n");
307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (async->mmap_count) {
310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice is mmapped, cannot resize buffer\n");
311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!async->prealloc_buf)
315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure buffer is an integral number of pages
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		 * (we round up) */
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK;
320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = comedi_buf_alloc(dev, s, bc.size);
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return ret;
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->buf_change) {
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->buf_change(dev, s, bc.size);
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret < 0)
328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				return ret;
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			dev->minor, bc.subdevice, async->prealloc_bufsz);
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
338476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &bc, sizeof(comedi_bufconfig)))
340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
359476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
360476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    struct file *file)
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_devinfo devinfo;
363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
364476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
365476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
366476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	comedi_subdevice *read_subdev =
367476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
368476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	comedi_subdevice *write_subdev =
369476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
379476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
381476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
383476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
384476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
386476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &devinfo, sizeof(comedi_devinfo)))
390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
409476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
410476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			     void *file)
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdinfo *tmp, *us;
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	tmp = kcalloc(dev->n_subdevices, sizeof(comedi_subdinfo), GFP_KERNEL);
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
436476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
468476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   dev->n_subdevices * sizeof(comedi_subdinfo));
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
489476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg)
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_chaninfo it;
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&it, arg, sizeof(comedi_chaninfo)))
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
505476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(lsampl_t)))
506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
513476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
529476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
530476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
531476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan*sizeof(unsigned int)))
532476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
533476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
553476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_bufinfo_ioctl(comedi_device *dev, void *arg)
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_bufinfo bi;
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async;
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&bi, arg, sizeof(comedi_bufinfo)))
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
582476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
583476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
590476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
599476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
606476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int parse_insn(comedi_device *dev, comedi_insn *insn, lsampl_t *data,
607476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		      void *file);
608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	COMEDI_INSNLIST
610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	synchronous instructions
611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	arg:
613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		pointer to sync cmd structure
614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	reads:
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		sync cmd struct at arg
617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		instruction list
618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for writes)
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	writes:
621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for reads)
622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
625476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file)
626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_insnlist insnlist;
628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_insn *insns = NULL;
629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lsampl_t *data = NULL;
630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist)))
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	data = kmalloc(sizeof(lsampl_t) * MAX_SAMPLES, GFP_KERNEL);
637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	insns = kmalloc(sizeof(comedi_insn) * insnlist.n_insns, GFP_KERNEL);
644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
651476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   sizeof(comedi_insn) * insnlist.n_insns)) {
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
665476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					   insns[i].n * sizeof(lsampl_t))) {
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
676476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 insns[i].n * sizeof(lsampl_t))) {
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
686476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
687476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
688476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
695476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int check_insn_config_length(comedi_insn *insn, lsampl_t *data)
696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
697476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
698476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
742476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* by default we allow the insn since we don't have checks for
743476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	 * all possible cases yet */
744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
745476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		rt_printk("comedi: no check for data length of config insn id "
746476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  "%i is implemented.\n"
747476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  " Add a check to %s in %s.\n"
748476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  " Assuming n=%i is correct.\n", data[0], __func__,
749476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  __FILE__, insn->n);
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
756476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int parse_insn(comedi_device *dev, comedi_insn *insn, lsampl_t *data,
757476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		      void *file)
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		lsampl_t maxdata;
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
846476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, 1, &insn->chanspec);
847476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
865476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
866476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
898476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	COMEDI_INSN
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	synchronous instructions
905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	arg:
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		pointer to insn
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	reads:
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		comedi_insn struct at arg
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for writes)
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	writes:
914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for reads)
915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
916476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_insn_ioctl(comedi_device *dev, void *arg, void *file)
917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_insn insn;
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lsampl_t *data = NULL;
920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	data = kmalloc(sizeof(lsampl_t) * MAX_SAMPLES, GFP_KERNEL);
923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&insn, arg, sizeof(comedi_insn))) {
929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(data, insn.data, insn.n * sizeof(lsampl_t))) {
938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(insn.data, data, insn.n * sizeof(lsampl_t))) {
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
953476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
954476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMD
961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command ioctl
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
974476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cmd_ioctl(comedi_device *dev, void *arg, void *file)
975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cmd user_cmd;
977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async;
979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
986476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1037476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1042476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1050476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
1057476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1058476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1068476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1089476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1090476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1091476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_RT) {
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_switch_to_rt(dev) == 0)
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT);
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1107476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1128476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file)
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cmd user_cmd;
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1140476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1171476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1179476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
1186476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, user_cmd.chanlist_len, chanlist);
1187476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1197476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1205476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1206476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1226476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file)
1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&s->spin_lock, flags);
1237476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1239476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1270476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file)
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1310476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file)
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1346476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_poll_ioctl(comedi_device *dev, unsigned int arg, void *file)
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1369476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int do_cancel(comedi_device *dev, comedi_subdevice *s)
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area)
1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async;
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev;
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
1395476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	.close =	comedi_unmap,
1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1401476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1402476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async = NULL;
1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1418476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1420476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1422476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
1452476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    page_to_pfn(virt_to_page(async->
1453476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							     buf_page_list[i].
1454476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							     virt_addr)),
1455476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    PAGE_SIZE, PAGE_SHARED)) {
1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1468476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1473476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic unsigned int comedi_poll(struct file *file, poll_table *wait)
1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1477476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1478476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *read_subdev;
1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *write_subdev;
1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1495476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1496476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1497476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1504476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1505476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1507476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1508476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1509476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1510476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
1520476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    loff_t *offset)
1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async;
1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1527476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1528476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1563476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1566476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1574476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1591476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1601476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1618476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
1622476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   loff_t *offset)
1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async;
1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1629476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1630476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1665476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1666476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1668476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1676476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1703476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1719476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1726476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
1732476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanvoid do_become_nonbusy(comedi_device *dev, comedi_subdevice *s)
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async = s->async;
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_get_subdevice_runflags(s) & SRF_RT) {
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_switch_to_non_rt(dev);
1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, SRF_RT, 0);
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1747476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1748476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	char mod[32];
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1758476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1759476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (capable(CAP_SYS_MODULE) && dev->in_request_module)
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	sprintf(mod, "char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	request_module(mod);
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached && !capable(CAP_SYS_MODULE)) {
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("not attached and not CAP_SYS_MODULE\n");
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1817476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 0 && dev->open)
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->open(dev);
1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1830476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1831476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s = NULL;
1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1842476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1844476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1848476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1852476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1859476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1868476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1869476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1870476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device *dev = dev_file_info->device;
1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
1877476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .owner =		THIS_MODULE,
1878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_UNLOCKED_IOCTL
1879476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .unlocked_ioctl =	comedi_unlocked_ioctl,
1880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
1881476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .ioctl =		comedi_ioctl,
1882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_COMPAT_IOCTL
1884476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .compat_ioctl =	comedi_compat_ioctl,
1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1886476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .open =		comedi_open,
1887476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .release =	comedi_close,
1888476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .read =		comedi_read,
1889476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .write =		comedi_write,
1890476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .mmap =		comedi_mmap,
1891476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .poll =		comedi_poll,
1892476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .fasync =		comedi_fasync,
1893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1895476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1901476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
19021dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1911476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1912476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1914476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1915476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1918476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1926476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
1931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		printk("comedi: failed to create class");
1932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1934476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1941476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19421dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1945476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1949476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_rt_init();
1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_register_ioctl32();
1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
1966476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
1968476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_rt_cleanup();
1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_unregister_ioctl32();
1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1984476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanvoid comedi_error(const comedi_device *dev, const char *s)
1985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
1987476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		  s);
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1990476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanvoid comedi_event(comedi_device *dev, comedi_subdevice *s)
1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_async *async = s->async;
1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1996476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->
2002476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (dev->rt) {
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT
2021476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				/* pend wake up */
2022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				comedi_rt_pend_wakeup(&async->wait_head);
2023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
2024476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				printk
2025476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    ("BUG: comedi_event() code unreachable\n");
2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			} else {
2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				wake_up_interruptible(&async->wait_head);
2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (s->subdev_flags & SDF_CMD_READ) {
2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					kill_fasync(&dev->async_queue, SIGIO,
2031476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						    POLL_IN);
2032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (s->subdev_flags & SDF_CMD_WRITE) {
2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					kill_fasync(&dev->async_queue, SIGIO,
2035476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						    POLL_OUT);
2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			/* XXX bug here.  If subdevice A is rt, and
2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * subdevice B tries to callback to a normal
2043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * linux kernel function, it will be at the
2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * wrong priority.  Since this isn't very
2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * common, I'm not going to worry about it. */
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2051476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanvoid comedi_set_subdevice_runflags(comedi_subdevice *s, unsigned mask,
2052476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   unsigned bits)
2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&s->spin_lock, flags);
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags &= ~mask;
2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags |= (bits & mask);
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2062476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanunsigned comedi_get_subdevice_runflags(comedi_subdevice *s)
2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&s->spin_lock, flags);
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2073476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic int is_device_busy(comedi_device *dev)
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdevice *s;
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_device_init(comedi_device *dev)
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(dev, 0, sizeof(comedi_device));
2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_device_cleanup(comedi_device *dev)
2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2102476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2103476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device_create_result_type *csdev;
2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2118476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2119476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = kzalloc(sizeof(comedi_device), GFP_KERNEL);
2121476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
2126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2127476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2128476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2134476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2138476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		rt_printk
2139476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    ("comedi: error: ran out of minor numbers for board device files.\n");
2140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2144476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2145476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2146476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2148476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
2149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2163476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
2164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device *dev = info->device;
2165476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2166476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2167476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2168476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s)
2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device_create_result_type *csdev;
2182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2185476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2186476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2191476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2192476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2198476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2200476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		rt_printk
2201476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    ("comedi: error: ran out of minor numbers for board device files.\n");
2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2206476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2207476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2208476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2209476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2211476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
2212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_subdevice_minor(comedi_subdevice *s)
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2220476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2221476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2223476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
2231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2233476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
2246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2251