comedi_fops.c revision ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3f
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
7271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devconfig_ioctl(struct comedi_device *dev, comedi_devconfig *arg);
7371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
7471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devinfo_ioctl(struct comedi_device *dev, comedi_devinfo *arg,
75476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    struct file *file);
7671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_subdinfo_ioctl(struct comedi_device *dev, comedi_subdinfo *arg,
77476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			     void *file);
7871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_chaninfo_ioctl(struct comedi_device *dev, comedi_chaninfo *arg);
7971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
8071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
8171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
8271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
8371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
8471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
8571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
8671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
8771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, void *file);
8871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton
8934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonextern void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s);
9034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
91ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
92ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on);
93ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
9471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct 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);
10771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int rc;
109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
11053b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	if (dev_file_info == NULL || dev_file_info->device == NULL)
11153b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess		return -ENODEV;
11253b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	dev = dev_file_info->device;
11353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess
114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* Device config is special, because it must work on
117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * an unconfigured device. */
118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cmd == COMEDI_DEVCONFIG) {
119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devconfig_ioctl(dev, (void *)arg);
120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENODEV;
126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (cmd) {
130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFCONFIG:
131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufconfig_ioctl(dev, (void *)arg);
132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_DEVINFO:
134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devinfo_ioctl(dev, (void *)arg, file);
135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_SUBDINFO:
137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_subdinfo_ioctl(dev, (void *)arg, file);
138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CHANINFO:
140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_chaninfo_ioctl(dev, (void *)arg);
141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_RANGEINFO:
143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_rangeinfo_ioctl(dev, (void *)arg);
144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFINFO:
146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufinfo_ioctl(dev, (void *)arg);
147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmd_ioctl(dev, (void *)arg, file);
159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmdtest_ioctl(dev, (void *)arg, file);
162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insnlist_ioctl(dev, (void *)arg, file);
165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insn_ioctl(dev, (void *)arg, file);
168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
177476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
19571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devconfig_ioctl(struct comedi_device *dev, comedi_devconfig *arg)
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_devconfig it;
198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
208476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&it, arg, sizeof(comedi_devconfig)))
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
233476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
238476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
242476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
248476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
249476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
27571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_bufconfig bc;
278d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
27934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&bc, arg, sizeof(comedi_bufconfig)))
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (bc.size > async->max_bufsize)
307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice is busy, cannot resize buffer\n");
311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (async->mmap_count) {
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice is mmapped, cannot resize buffer\n");
315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!async->prealloc_buf)
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure buffer is an integral number of pages
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		 * (we round up) */
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK;
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = comedi_buf_alloc(dev, s, bc.size);
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return ret;
328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->buf_change) {
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->buf_change(dev, s, bc.size);
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret < 0)
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				return ret;
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			dev->minor, bc.subdevice, async->prealloc_bufsz);
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
342476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &bc, sizeof(comedi_bufconfig)))
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
36371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devinfo_ioctl(struct comedi_device *dev, comedi_devinfo *arg,
364476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    struct file *file)
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_devinfo devinfo;
367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
368476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
369476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
37034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
371476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
37234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
383476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
385476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
387476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
388476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
390476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &devinfo, sizeof(comedi_devinfo)))
394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
41371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_subdinfo_ioctl(struct comedi_device *dev, comedi_subdinfo *arg,
414476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			     void *file)
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_subdinfo *tmp, *us;
41834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	tmp = kcalloc(dev->n_subdevices, sizeof(comedi_subdinfo), GFP_KERNEL);
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
440476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
472476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   dev->n_subdevices * sizeof(comedi_subdinfo));
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
49371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_chaninfo_ioctl(struct comedi_device *dev, comedi_chaninfo *arg)
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
49534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_chaninfo it;
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&it, arg, sizeof(comedi_chaninfo)))
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
509790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
517476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
530476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
533476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
534476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
535476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan*sizeof(unsigned int)))
536476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
537476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
55771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg)
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_bufinfo bi;
56034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
561d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&bi, arg, sizeof(comedi_bufinfo)))
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
586476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
587476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
594476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
603476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
61071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int parse_insn(struct comedi_device *dev, comedi_insn *insn, unsigned int *data,
611476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		      void *file);
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	COMEDI_INSNLIST
614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	synchronous instructions
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	arg:
617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		pointer to sync cmd structure
618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	reads:
620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		sync cmd struct at arg
621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		instruction list
622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for writes)
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	writes:
625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for reads)
626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
62971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_insnlist insnlist;
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_insn *insns = NULL;
633790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist)))
638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
640790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	insns = kmalloc(sizeof(comedi_insn) * insnlist.n_insns, GFP_KERNEL);
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
655476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   sizeof(comedi_insn) * insnlist.n_insns)) {
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
669790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
680790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
690476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
691476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
692476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
699790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pembertonstatic int check_insn_config_length(comedi_insn *insn, unsigned int *data)
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
701476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
702476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
746476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* by default we allow the insn since we don't have checks for
747476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	 * all possible cases yet */
748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
749476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		rt_printk("comedi: no check for data length of config insn id "
750476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  "%i is implemented.\n"
751476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  " Add a check to %s in %s.\n"
752476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  " Assuming n=%i is correct.\n", data[0], __func__,
753476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			  __FILE__, insn->n);
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
76071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int parse_insn(struct comedi_device *dev, comedi_insn *insn, unsigned int *data,
761476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		      void *file)
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
76334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
828790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
850476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, 1, &insn->chanspec);
851476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
869476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
870476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
902476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	COMEDI_INSN
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	synchronous instructions
909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	arg:
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		pointer to insn
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	reads:
914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		comedi_insn struct at arg
915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for writes)
916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	writes:
918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for reads)
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
92071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_insn insn;
923790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
926790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(&insn, arg, sizeof(comedi_insn))) {
933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
941790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		if (copy_from_user(data, insn.data, insn.n * sizeof(unsigned int))) {
942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
950790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) {
951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
957476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
958476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMD
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command ioctl
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
97871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
980ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
98134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
982d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
986ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
990476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1041476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1046476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1054476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
1061476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1062476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1072476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
1075ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1093476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1094476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1095476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_RT) {
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_switch_to_rt(dev) == 0)
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT);
1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1111476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
113271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file)
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1134ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
113534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1140ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1144476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1175476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1183476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
1190476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, user_cmd.chanlist_len, chanlist);
1191476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1201476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1204ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1209476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1210476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
123071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
123434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&s->spin_lock, flags);
1241476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1243476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
127471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
127634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
131471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
131634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
135071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
135234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
137334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area)
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1387d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
138871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
1399476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	.close =	comedi_unmap,
1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1405476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1406476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
140771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1408d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
141434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1422476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1424476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1426476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
1456476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    page_to_pfn(virt_to_page(async->
1457476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							     buf_page_list[i].
1458476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							     virt_addr)),
1459476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    PAGE_SIZE, PAGE_SHARED)) {
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1472476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1477476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic unsigned int comedi_poll(struct file *file, poll_table *wait)
1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1481476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1482476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
148371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
148434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
148534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1499476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1500476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1501476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1508476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1509476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1511476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1512476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1513476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1514476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
1524476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    loff_t *offset)
1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
152634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1527d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1531476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1532476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
153371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1567476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1570476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1578476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1595476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1605476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1622476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
1626476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   loff_t *offset)
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
162834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1629d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1633476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1634476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
163571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1669476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1670476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1672476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1680476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1707476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1723476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1730476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
173634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1738d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_get_subdevice_runflags(s) & SRF_RT) {
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_switch_to_non_rt(dev);
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, SRF_RT, 0);
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1751476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1752476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1761476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1762476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
176371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info ? dev_file_info->device : NULL;
1764979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (capable(CAP_SYS_MODULE) && dev->in_request_module)
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
179856d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached && !capable(CAP_SYS_MODULE)) {
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("not attached and not CAP_SYS_MODULE\n");
1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1820476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 0 && dev->open)
1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->open(dev);
1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1833476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1834476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
183571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
183634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1845476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1847476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1851476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1855476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1862476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1871476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1872476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1873476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
187471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
1880476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .owner =		THIS_MODULE,
1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_UNLOCKED_IOCTL
1882476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .unlocked_ioctl =	comedi_unlocked_ioctl,
1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
1884476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .ioctl =		comedi_ioctl,
1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_COMPAT_IOCTL
1887476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .compat_ioctl =	comedi_compat_ioctl,
1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1889476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .open =		comedi_open,
1890476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .release =	comedi_close,
1891476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .read =		comedi_read,
1892476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .write =		comedi_write,
1893476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .mmap =		comedi_mmap,
1894476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .poll =		comedi_poll,
1895476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman      .fasync =		comedi_fasync,
1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1898476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1904476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
19051dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1914476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1915476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1917a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
1918a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1919a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
1920a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1921a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1922a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
1923a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
1924a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1925a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
1926a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
1927a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1928a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
1929a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
1930a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1931a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
1932a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1933476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1934476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1937476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1945476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		printk("comedi: failed to create class");
1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1953476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1960476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19611dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1964476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1968476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_rt_init();
1974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_register_ioctl32();
1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
1985476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
1987476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
1990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_rt_cleanup();
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_unregister_ioctl32();
1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
200371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
2006476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		  s);
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
200934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2011d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
2012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2015476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->
2021476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
2023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
2025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (dev->rt) {
2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT
2040476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				/* pend wake up */
2041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				comedi_rt_pend_wakeup(&async->wait_head);
2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
2043476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				printk
2044476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    ("BUG: comedi_event() code unreachable\n");
2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			} else {
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				wake_up_interruptible(&async->wait_head);
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (s->subdev_flags & SDF_CMD_READ) {
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					kill_fasync(&dev->async_queue, SIGIO,
2050476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						    POLL_IN);
2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (s->subdev_flags & SDF_CMD_WRITE) {
2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					kill_fasync(&dev->async_queue, SIGIO,
2054476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						    POLL_OUT);
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			/* XXX bug here.  If subdevice A is rt, and
2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * subdevice B tries to callback to a normal
2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * linux kernel function, it will be at the
2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * wrong priority.  Since this isn't very
2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			 * common, I'm not going to worry about it. */
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
207034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
2071476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   unsigned bits)
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&s->spin_lock, flags);
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags &= ~mask;
2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags |= (bits & mask);
2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
208134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&s->spin_lock, flags);
2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
209271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
209434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
211171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_init(struct comedi_device *dev)
2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
211371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
211971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_cleanup(struct comedi_device *dev)
2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2121476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
21330bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2137476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2138476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
213971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2140476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
2145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2146476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2147476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2153476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2157476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		rt_printk
2158476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    ("comedi: error: ran out of minor numbers for board device files.\n");
2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2163476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2164476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2165476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2167476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
2168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2182476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
218371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2184476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2185476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2186476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2187476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
219634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonint comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s)
2197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
22000bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2204476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2205476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
22104c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2211476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2217476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2219476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		rt_printk
2220476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    ("comedi: error: ran out of minor numbers for board device files.\n");
2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2225476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2226476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2227476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2228476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2230476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
2231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
223434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2239476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2241476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2242476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
2250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2252476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
2265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2270