comedi_fops.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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
661dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrint comedi_num_legacy_minors = 0;
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 Schleef#ifdef HAVE_UNLOCKED_IOCTL
114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
115476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				  unsigned long arg)
116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_ioctl(struct inode *inode, struct file *file,
118476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			unsigned int cmd, unsigned long arg)
119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
123476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
12471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int rc;
126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12753b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	if (dev_file_info == NULL || dev_file_info->device == NULL)
12853b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess		return -ENODEV;
12953b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	dev = dev_file_info->device;
13053b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess
131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* Device config is special, because it must work on
134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * an unconfigured device. */
135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cmd == COMEDI_DEVCONFIG) {
136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devconfig_ioctl(dev, (void *)arg);
137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENODEV;
143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (cmd) {
147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFCONFIG:
148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufconfig_ioctl(dev, (void *)arg);
149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_DEVINFO:
151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devinfo_ioctl(dev, (void *)arg, file);
152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_SUBDINFO:
154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_subdinfo_ioctl(dev, (void *)arg, file);
155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CHANINFO:
157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_chaninfo_ioctl(dev, (void *)arg);
158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_RANGEINFO:
160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_rangeinfo_ioctl(dev, (void *)arg);
161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFINFO:
163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufinfo_ioctl(dev, (void *)arg);
164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmd_ioctl(dev, (void *)arg, file);
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmdtest_ioctl(dev, (void *)arg, file);
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insnlist_ioctl(dev, (void *)arg, file);
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insn_ioctl(dev, (void *)arg, file);
185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
194476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
2120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
2130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_devconfig *arg)
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2150707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	struct comedi_devconfig it;
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
226476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2340707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
251476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
256476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
260476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
266476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
267476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
29371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
295be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	struct comedi_bufconfig bc;
296d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
29734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
298883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval = 0;
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
300be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = resize_async_buffer(dev, s, async, bc.size);
325883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
326883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
332476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
333be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
3540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_devinfo *arg, struct file *file)
355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
356063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	struct comedi_devinfo devinfo;
357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
358476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
359476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
36034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
361476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
36234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
363476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
375476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
377476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
378476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
380476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
383063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
4040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdinfo *arg, void *file)
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
407bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton	struct comedi_subdinfo *tmp, *us;
40834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
4100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	tmp =
4110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
4120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
432476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
464bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
4860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_chaninfo *arg)
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
48834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
489a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	struct comedi_chaninfo it;
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
491a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
502790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
510476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
523476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
527476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
5280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 s->n_chan * sizeof(unsigned int)))
529476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
530476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
55071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg)
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
5529aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	struct comedi_bufinfo bi;
55334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
554d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5569aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
579476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
580476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
587476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
596476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
5979aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
6040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file);
605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	COMEDI_INSNLIST
607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	synchronous instructions
608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	arg:
610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		pointer to sync cmd structure
611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	reads:
613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		sync cmd struct at arg
614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		instruction list
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for writes)
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	writes:
618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for reads)
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
62271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
624da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	struct comedi_insnlist insnlist;
62590035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn *insns = NULL;
626790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
630da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
633790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	insns =
6410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
64990035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
663790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
674790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
684476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
685476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
686476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn,
6940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    unsigned int *data)
695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
696476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
697476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
7410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* by default we allow the insn since we don't have checks for
7420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 * all possible cases yet */
743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
7445f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		printk("comedi: no check for data length of config insn id "
7450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "%i is implemented.\n"
7460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Add a check to %s in %s.\n"
7470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Assuming n=%i is correct.\n", data[0], __func__,
7480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       __FILE__, insn->n);
749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
7560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file)
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
75834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
823790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
845476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, 1, &insn->chanspec);
846476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
864476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
865476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
897476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	COMEDI_INSN
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	synchronous instructions
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	arg:
906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		pointer to insn
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	reads:
90990035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton * 		struct comedi_insn struct at arg
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for writes)
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 	writes:
913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 		data (for reads)
914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
91571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
91790035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn insn;
918790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
921790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
92790035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
9360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (copy_from_user
9370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (data, insn.data, insn.n * sizeof(unsigned int))) {
938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
9460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (copy_to_user
9470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (insn.data, data, insn.n * sizeof(unsigned int))) {
948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
954476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
955476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMD
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command ioctl
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
97571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
977ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
97834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
979d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
983ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
987476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1038476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1043476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1051476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
1058476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1059476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1069476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
1072ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1090476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1091476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1092476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1101476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
112271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file)
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1124ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
112534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1130ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1134476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1165476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1173476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
1180476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		ret = check_chanlist(s, user_cmd.chanlist_len, chanlist);
1181476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1191476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1194ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1199476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1200476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
12210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
122534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12315f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1232476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1234476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
12365f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
12650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
12660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
126834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
13070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
130934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
13440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
134634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
136734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area)
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1381d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
138271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
13930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.close = comedi_unmap,
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1399476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1400476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
140171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1402d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
140834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1416476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1418476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1420476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
14500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    page_to_pfn(virt_to_page
14510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						(async->buf_page_list
14520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						 [i].virt_addr)), PAGE_SIZE,
14530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PAGE_SHARED)) {
1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1466476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
14710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait)
1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1475476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1476476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
147771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
147834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
147934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1493476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1494476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1495476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1502476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1503476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1505476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1506476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1507476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1508476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
15180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    loff_t * offset)
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
152034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1521d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
152771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1561476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1564476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1572476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1589476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1599476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1616476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
16200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   loff_t * offset)
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
162234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1623d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1627476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1628476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
162971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1663476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1664476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1666476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1674476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1701476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1717476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1724476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
173034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1732d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1739476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1740476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1749476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1750476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
17510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev =
17520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dev_file_info ? dev_file_info->device : NULL;
1753979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1775a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1780a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
178756d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1793a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1794a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1809476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 0 && dev->open)
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->open(dev);
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1822476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1823476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
182471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
182534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1834476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1836476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1840476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1844476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1851476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1860476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1861476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1862476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
186371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
18690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.owner = THIS_MODULE,
1870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_UNLOCKED_IOCTL
18710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.unlocked_ioctl = comedi_unlocked_ioctl,
1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else
18730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.ioctl = comedi_ioctl,
1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_COMPAT_IOCTL
18760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.compat_ioctl = comedi_compat_ioctl,
1877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
18780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.open = comedi_open,
18790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.release = comedi_close,
18800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.read = comedi_read,
18810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.write = comedi_write,
18820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.mmap = comedi_mmap,
18830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.poll = comedi_poll,
18840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.fasync = comedi_fasync,
1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1887476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1893476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
18941dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1903476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1904476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1906a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
1907a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1908a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
1909a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1910a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1911a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
1912a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
1913a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1914a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
1915a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
1916a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1917a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
1918a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
1919a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1920a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
1921a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1922476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1923476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1926476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1934476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		printk("comedi: failed to create class");
1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1942476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1949476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19501dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1953476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1957476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_register_ioctl32();
1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
1972476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
1974476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_unregister_ioctl32();
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
1985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
198771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
19895f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name, s);
1990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
199234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1994d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1998476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (s->
20040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
20050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     COMEDI_CB_OVERFLOW)) {
2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2021fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			wake_up_interruptible(&async->wait_head);
2022fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			if (s->subdev_flags & SDF_CMD_READ) {
20230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2024fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			}
2025fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			if (s->subdev_flags & SDF_CMD_WRITE) {
20260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
203634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
2037476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   unsigned bits)
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20415f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags &= ~mask;
2043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags |= (bits & mask);
20445f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
204734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20525f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
20545f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
205871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
206034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
207771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_init(struct comedi_device *dev)
2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
207971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
208571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_cleanup(struct comedi_device *dev)
2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2087476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2088476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
20990bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2101883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2104476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2105476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
210671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2107476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
21125f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2113476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2114476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
21195f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2120476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
21240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: error: ran out of minor numbers for board device files.\n");
2126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2130476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2131476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2132476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2134883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2135883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2136883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2140883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2141883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2142883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2143883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2144883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2148883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2149883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2150883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2151883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2152883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2156883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2157883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2158883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2159883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2160883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2164883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2165883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2166883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
21765f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
21795f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2181476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
218271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2183476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2184476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2185476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2186476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2195883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev,
2196883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				 struct comedi_subdevice *s)
2197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
22000bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2202883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2205476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2206476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
22105f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
22114c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2212476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
22175f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2218476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
22200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: error: ran out of minor numbers for board device files.\n");
2222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2226476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2227476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2228476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2229476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2231883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2232883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2233883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2237883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2238883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2239883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2240883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2241883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2245883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2246883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2247883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2248883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2249883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2253883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2254883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2255883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2256883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2257883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2261883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2262883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2263883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
226734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2272476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2273476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2274476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2275476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
22805f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
22835f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2285476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
22985f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
23005f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2303883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2304883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
2305883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
2306883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size)
2307883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2308883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2309883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2310883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (new_size > async->max_bufsize)
2311883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EPERM;
2312883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->busy) {
2314883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is busy, cannot resize buffer\n");
2315883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2316883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2317883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (async->mmap_count) {
2318883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2319883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (!async->prealloc_buf)
2323883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2325883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	/* make sure buffer is an integral number of pages
23260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 * (we round up) */
2327883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2328883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2329883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = comedi_buf_alloc(dev, s, new_size);
2330883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2331883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2332883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->buf_change) {
2334883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = s->buf_change(dev, s, new_size);
2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
2336883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
2337883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		dev->minor, s - dev->subdevices, async->prealloc_bufsz);
2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return 0;
2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */
2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024;
2347883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2348883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev,
2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				       struct device_attribute *attr, char *buf)
2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2354883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2356883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2358883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async) {
2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = read_subdevice->async->max_bufsize /
23620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2363883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
23640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2370883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev,
2371883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2372883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					const char *buf, size_t count)
2373883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2374883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2376883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2377883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2379883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2380883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2381883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
23820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2383883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
23840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
23850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2389883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2390883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2393883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2395883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	read_subdevice->async->max_bufsize = new_max_size;
2396883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2397883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2398883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2400883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = {
2402883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_read_buffer_kb",
24040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_read_buffer_kb,
2406883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_read_buffer_kb
2407883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2408883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2409883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev,
2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				   struct device_attribute *attr, char *buf)
2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2415883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2417883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2419883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
24200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
24210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    read_subdevice->async) {
2422883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
24230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev,
2432883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr,
2433883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    const char *buf, size_t count)
2434883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2438883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2439883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2441883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2443883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
24470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2454883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, read_subdevice,
2458883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     read_subdevice->async, new_size);
2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2461883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2462883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2463883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = {
2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "read_buffer_kb",
24690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_read_buffer_kb,
2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_read_buffer_kb
2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev,
2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					char *buf)
2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2481883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
24820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2483883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2484883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2485883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2486883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2488883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = write_subdevice->async->max_bufsize /
24890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2490883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2497883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev,
2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 struct device_attribute *attr,
2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 const char *buf, size_t count)
2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2503883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2504883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2506883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2507883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2510883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
25120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	write_subdevice->async->max_bufsize = new_max_size;
2523883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2527883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = {
2529883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_write_buffer_kb",
25310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_write_buffer_kb,
2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_write_buffer_kb
2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev,
2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr, char *buf)
2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2542883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2544883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2546883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2548883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2549883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
25500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2551883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2553883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev,
2559883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     struct device_attribute *attr,
2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     const char *buf, size_t count)
2561883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2565883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2566883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2568883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2570883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
25740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2581883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, write_subdevice,
25850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     write_subdevice->async, new_size);
2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2587883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2588883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2589883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2590883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2591883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2592883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2593883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = {
2594883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "write_buffer_kb",
25960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2597883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_write_buffer_kb,
2598883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_write_buffer_kb
2599883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2600