comedi_fops.c revision 3fffdf2045d0dbca3833f8f54ae41ce5f2c0b8fa
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>
47883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess#include <linux/stat.h>
48ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
49476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/io.h>
50476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/uaccess.h>
51ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
52476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman/* #include "kvmem.h" */
53ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
54ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_AUTHOR("http://www.comedi.org");
55ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_DESCRIPTION("Comedi core module");
56ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_LICENSE("GPL");
57ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
58ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_DEBUG
59ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_debug;
60ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_param(comedi_debug, int, 0644);
61ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
62ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
636a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottint comedi_autoconfig = 1;
646a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottmodule_param(comedi_autoconfig, bool, 0444);
656a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbott
666705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelminiint comedi_num_legacy_minors;
671dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrmodule_param(comedi_num_legacy_minors, int, 0444);
681dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr
69ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic DEFINE_SPINLOCK(comedi_file_info_table_lock);
70476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic struct comedi_device_file_info
710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral*comedi_file_info_table[COMEDI_NUM_MINORS];
72476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_devconfig *arg);
7571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_devinfo *arg, struct file *file);
780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdinfo *arg, void *file);
800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_chaninfo *arg);
8271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
8371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
9071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
9171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
9271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
9571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton
960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralextern void do_become_nonbusy(struct comedi_device *dev,
970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_subdevice *s);
9834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
99ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on);
101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
10271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev);
103883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
104883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
105883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size);
106883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
107883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* declarations for sysfs attribute files */
108883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb;
109883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb;
110883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb;
111883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb;
112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
114476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				  unsigned long arg)
115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
117476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
118476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
11971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int rc;
121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12253b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	if (dev_file_info == NULL || dev_file_info->device == NULL)
12353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess		return -ENODEV;
12453b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	dev = dev_file_info->device;
12553b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess
126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* Device config is special, because it must work on
129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * an unconfigured device. */
130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cmd == COMEDI_DEVCONFIG) {
131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devconfig_ioctl(dev, (void *)arg);
132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENODEV;
138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (cmd) {
142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFCONFIG:
143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufconfig_ioctl(dev, (void *)arg);
144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_DEVINFO:
146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devinfo_ioctl(dev, (void *)arg, file);
147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_SUBDINFO:
149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_subdinfo_ioctl(dev, (void *)arg, file);
150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CHANINFO:
152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_chaninfo_ioctl(dev, (void *)arg);
153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_RANGEINFO:
155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_rangeinfo_ioctl(dev, (void *)arg);
156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFINFO:
158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufinfo_ioctl(dev, (void *)arg);
159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmd_ioctl(dev, (void *)arg, file);
171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmdtest_ioctl(dev, (void *)arg, file);
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insnlist_ioctl(dev, (void *)arg, file);
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insn_ioctl(dev, (void *)arg, file);
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
189476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
2070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
2080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_devconfig *arg)
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2100707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	struct comedi_devconfig it;
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
221476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2290707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
235476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
246476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
251476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
255476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
261476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
262476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
28871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
290be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	struct comedi_bufconfig bc;
291d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
29234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
293883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval = 0;
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
295be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
319883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = resize_async_buffer(dev, s, async, bc.size);
320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
327476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
328be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
3490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_devinfo *arg, struct file *file)
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
351063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	struct comedi_devinfo devinfo;
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
353476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
354476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
35534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
356476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
35734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
358476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
368476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
370476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
372476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
375476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
378063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
3990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdinfo *arg, void *file)
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
402bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton	struct comedi_subdinfo *tmp, *us;
40334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
4050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	tmp =
4060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
4070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
427476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
459bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
4810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_chaninfo *arg)
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
48334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
484a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	struct comedi_chaninfo it;
485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
486a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
497790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
505476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
518476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
521476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
522476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
5230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 s->n_chan * sizeof(unsigned int)))
524476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
54571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg)
546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
5479aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	struct comedi_bufinfo bi;
54834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
549d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5519aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
574476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
575476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
582476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
591476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
5929aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
5990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file);
600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
60120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSNLIST
60220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
60420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
60520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to sync cmd structure
606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
60720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
60820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		sync cmd struct at arg
60920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		instruction list
61020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
61220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
61320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
61771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
619da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	struct comedi_insnlist insnlist;
62090035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn *insns = NULL;
621790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
625da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
628790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	insns =
6360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
64490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
658790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
669790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
679476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
680476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
681476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn,
6890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    unsigned int *data)
690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
691476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
692476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
7360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* by default we allow the insn since we don't have checks for
7370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 * all possible cases yet */
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
7393fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_WARNING
7403fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		       "comedi: no check for data length of config insn id "
7410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "%i is implemented.\n"
7420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Add a check to %s in %s.\n"
7430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Assuming n=%i is correct.\n", data[0], __func__,
7440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       __FILE__, insn->n);
745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
7520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file)
753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
75434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
819790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
841476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, 1, &insn->chanspec);
842476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
860476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
861476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
893476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
89820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSN
89920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
90120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
90220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to insn
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
90420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
90520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		struct comedi_insn struct at arg
90620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
90820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
90920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
91171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
91390035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn insn;
914790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
917790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
92390035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
9320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (copy_from_user
9330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (data, insn.data, insn.n * sizeof(unsigned int))) {
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
9420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (copy_to_user
9430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (insn.data, data, insn.n * sizeof(unsigned int))) {
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
950476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
951476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMD
958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command ioctl
959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
97171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
973ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
97434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
975d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
979ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
983476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1034476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1039476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1047476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
1054476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1055476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1065476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
1068ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1086476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1087476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1088476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1097476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
111871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file)
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1120ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
112134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1126ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1130476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1161476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1169476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
1176476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, user_cmd.chanlist_len, chanlist);
1177476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1187476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1190ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1195476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1196476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
12170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
122134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12275f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1228476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1230476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
12325f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
12610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
12620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
126434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
13030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
130534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
13400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
134234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
136334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area)
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1377d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
137871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
13890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.close = comedi_unmap,
1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1395476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1396476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
139771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1398d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
140434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1412476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1414476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1416476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
14460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    page_to_pfn(virt_to_page
14470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						(async->buf_page_list
14480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						 [i].virt_addr)), PAGE_SIZE,
14490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PAGE_SHARED)) {
1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1462476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
14670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait)
1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1471476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1472476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
147371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
147434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
147534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1489476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1490476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1491476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1498476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1499476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1501476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1502476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1503476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1504476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
15146705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
151634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1517d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1521476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1522476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
152371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1557476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1560476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1568476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1585476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1595476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1612476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
16166705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
161834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1619d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1623476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1624476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
162571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1659476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1660476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1662476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1670476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1697476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1713476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1720476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
172634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1728d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1735476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1736476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1745476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1746476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
17470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev =
17480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dev_file_info ? dev_file_info->device : NULL;
1749979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1771a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1776a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
178356d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1789a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1790a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1805476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 0 && dev->open)
1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->open(dev);
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1818476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1819476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
182071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
182134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1830476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1832476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1836476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1840476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1847476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1856476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1857476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1858476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
185971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
18650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.owner = THIS_MODULE,
18660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.unlocked_ioctl = comedi_unlocked_ioctl,
18670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.compat_ioctl = comedi_compat_ioctl,
18680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.open = comedi_open,
18690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.release = comedi_close,
18700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.read = comedi_read,
18710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.write = comedi_write,
18720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.mmap = comedi_mmap,
18730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.poll = comedi_poll,
18740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.fasync = comedi_fasync,
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1877476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1883476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
18841dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1893476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1894476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1896a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
1897a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1898a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
1899a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1900a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1901a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
1902a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
1903a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1904a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
1905a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
1906a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1907a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
1908a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
1909a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1910a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
1911a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1912476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1913476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1916476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1924476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
19293fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_ERR "comedi: failed to create class");
1930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1932476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1939476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19401dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1943476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1947476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
1960476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
1962476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
197371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
1974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
19753fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
19763fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	       dev->driver->driver_name, s);
1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
197934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1981d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1985476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
19900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (s->
19910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
19920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     COMEDI_CB_OVERFLOW)) {
1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2008fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			wake_up_interruptible(&async->wait_head);
20096705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_READ)
20100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
20116705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_WRITE)
20120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
202134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
2022476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   unsigned bits)
2023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20265f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags &= ~mask;
2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags |= (bits & mask);
20295f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
203234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20375f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
20395f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
204371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
204534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
206271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_init(struct comedi_device *dev)
2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
206471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
207071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_cleanup(struct comedi_device *dev)
2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2072476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2073476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
20840bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2086883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2089476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2090476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
209171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2092476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
20975f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2098476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2099476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
21045f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2105476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
21090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
211020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere
21110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: error: ran out of minor numbers for board device files.\n");
2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2116476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2117476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2118476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2120883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2121883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2122883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2126883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2127883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2128883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2129883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2130883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2134883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2135883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2136883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2137883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2138883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2142883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2143883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2144883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2145883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2146883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2150883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2151883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2152883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
21625f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
21655f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2167476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
216871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2169476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2170476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2171476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2172476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2181883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev,
2182883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				 struct comedi_subdevice *s)
2183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
21860bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2188883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2191476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2192476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
21965f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
21974c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2198476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
22035f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2204476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
22060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: error: ran out of minor numbers for board device files.\n");
2208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2212476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2213476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2214476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2215476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2217883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2218883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2219883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2223883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2224883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2225883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2226883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2227883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2231883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2232883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2233883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2234883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2235883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2239883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2240883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2241883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2242883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2243883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2247883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2248883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2249883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
225334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2258476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2259476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2260476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2261476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
22665f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
22695f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2271476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
22845f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
22865f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2289883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2290883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
2291883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
2292883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size)
2293883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2294883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2295883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2296883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (new_size > async->max_bufsize)
2297883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EPERM;
2298883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2299883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->busy) {
2300883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is busy, cannot resize buffer\n");
2301883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2302883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2303883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (async->mmap_count) {
2304883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2305883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2306883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2307883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2308883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (!async->prealloc_buf)
2309883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2310883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2311883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	/* make sure buffer is an integral number of pages
23120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 * (we round up) */
2313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2314883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2315883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = comedi_buf_alloc(dev, s, new_size);
2316883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2317883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2318883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2319883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->buf_change) {
2320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = s->buf_change(dev, s, new_size);
2321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
2322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
2323883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2325883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2326b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2327883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return 0;
2328883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2329883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2330883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */
2331883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2332883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024;
2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2334883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev,
2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				       struct device_attribute *attr, char *buf)
2336883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2337883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async) {
2347883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = read_subdevice->async->max_bufsize /
23480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
23500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2354883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2355883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2356883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev,
2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2358883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					const char *buf, size_t count)
2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2363883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
23680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
23700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
23710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2372883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2373883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2374883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2376883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2377883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2378883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2379883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2380883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2381883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	read_subdevice->async->max_bufsize = new_max_size;
2382883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2383883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2384883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2385883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = {
2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
23890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_read_buffer_kb",
23900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_read_buffer_kb,
2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_read_buffer_kb
2393883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2395883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev,
2396883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				   struct device_attribute *attr, char *buf)
2397883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2398883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2400883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2403883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2404883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
24060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
24070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    read_subdevice->async) {
2408883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
24090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2415883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2416883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2417883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev,
2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr,
2419883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    const char *buf, size_t count)
2420883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2421883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2422883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2423883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
24330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2434883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2438883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2439883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2440883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2441883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2443883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, read_subdevice,
2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     read_subdevice->async, new_size);
2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2446883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2447883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = {
2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "read_buffer_kb",
24550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_read_buffer_kb,
2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_read_buffer_kb
2458883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev,
2461883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2462883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					char *buf)
2463883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
24680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2469883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = write_subdevice->async->max_bufsize /
24750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2481883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2482883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2483883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev,
2484883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 struct device_attribute *attr,
2485883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 const char *buf, size_t count)
2486883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2488883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2489883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2490883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
24910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
24980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2503883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2504883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2505883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2506883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2507883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	write_subdevice->async->max_bufsize = new_max_size;
2509883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2510883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2511883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = {
2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_write_buffer_kb",
25170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_write_buffer_kb,
2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_write_buffer_kb
2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev,
2523883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr, char *buf)
2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2527883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2530883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
25360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2542883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2543883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2544883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev,
2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     struct device_attribute *attr,
2546883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     const char *buf, size_t count)
2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2548883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2549883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2550883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2551883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2552883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
25600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2561883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2565883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2566883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2567883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2568883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2570883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, write_subdevice,
25710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     write_subdevice->async, new_size);
2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2573883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = {
2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "write_buffer_kb",
25820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_write_buffer_kb,
2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_write_buffer_kb
2585883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2586