comedi_fops.c revision 0fd0ca75fd9eb0e9cde49c28ad227c2d8d049366
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;
6018736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_debug);
61ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_param(comedi_debug, int, 0644);
62ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
63ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
646a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottint comedi_autoconfig = 1;
656a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottmodule_param(comedi_autoconfig, bool, 0444);
666a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbott
676705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelminiint comedi_num_legacy_minors;
681dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrmodule_param(comedi_num_legacy_minors, int, 0444);
691dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr
70ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic DEFINE_SPINLOCK(comedi_file_info_table_lock);
71476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic struct comedi_device_file_info
720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral*comedi_file_info_table[COMEDI_NUM_MINORS];
73476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_devconfig *arg);
7671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_devinfo *arg, struct file *file);
790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdinfo *arg, void *file);
810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_chaninfo *arg);
8371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
8471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
9171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
9271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
9371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
9671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton
970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralextern void do_become_nonbusy(struct comedi_device *dev,
980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_subdevice *s);
9934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on);
102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
10371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev);
104883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
105883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
106883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size);
107883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
108883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* declarations for sysfs attribute files */
109883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb;
110883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb;
111883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb;
112883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb;
113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
115476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				  unsigned long arg)
116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
118476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
119476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
12071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int rc;
122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	if (dev_file_info == NULL || dev_file_info->device == NULL)
12453b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess		return -ENODEV;
12553b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	dev = dev_file_info->device;
12653b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess
127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* Device config is special, because it must work on
130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * an unconfigured device. */
131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cmd == COMEDI_DEVCONFIG) {
132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devconfig_ioctl(dev, (void *)arg);
133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENODEV;
139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (cmd) {
143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFCONFIG:
144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufconfig_ioctl(dev, (void *)arg);
145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_DEVINFO:
147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_devinfo_ioctl(dev, (void *)arg, file);
148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_SUBDINFO:
150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_subdinfo_ioctl(dev, (void *)arg, file);
151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CHANINFO:
153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_chaninfo_ioctl(dev, (void *)arg);
154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_RANGEINFO:
156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_rangeinfo_ioctl(dev, (void *)arg);
157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFINFO:
159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_bufinfo_ioctl(dev, (void *)arg);
160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmd_ioctl(dev, (void *)arg, file);
172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cmdtest_ioctl(dev, (void *)arg, file);
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insnlist_ioctl(dev, (void *)arg, file);
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_insn_ioctl(dev, (void *)arg, file);
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
190476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
2080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
2090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_devconfig *arg)
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2110707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	struct comedi_devconfig it;
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2300707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
236476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
247476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
252476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
256476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
262476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
263476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
28971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
291be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	struct comedi_bufconfig bc;
292d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
29334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
294883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval = 0;
295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
296be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = resize_async_buffer(dev, s, async, bc.size);
321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
328476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
329be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
3500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_devinfo *arg, struct file *file)
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
352063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	struct comedi_devinfo devinfo;
353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
354476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
355476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
35634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
357476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
35834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
359476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
369476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
371476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
374476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
376476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
379063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
4000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdinfo *arg, void *file)
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
403bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton	struct comedi_subdinfo *tmp, *us;
40434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
4060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	tmp =
4070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
4080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
428476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
460bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
4820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_chaninfo *arg)
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
48434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
485a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	struct comedi_chaninfo it;
486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
487a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
498790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
506476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
519476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
522476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
523476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
5240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 s->n_chan * sizeof(unsigned int)))
525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
54671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg)
547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
5489aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	struct comedi_bufinfo bi;
54934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
550d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5529aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
575476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
576476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
583476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
592476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
5939aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
6000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file);
601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
60220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSNLIST
60320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
60520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
60620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to sync cmd structure
607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
60820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
60920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		sync cmd struct at arg
61020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		instruction list
61120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
61320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
61420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
61871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
620da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	struct comedi_insnlist insnlist;
62190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn *insns = NULL;
622790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
626da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
629790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	insns =
6370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
64590035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
659790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
670790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
680476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
681476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
682476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn,
6900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    unsigned int *data)
691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
692476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
693476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
7370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* by default we allow the insn since we don't have checks for
7380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 * all possible cases yet */
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
7403fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_WARNING
7413fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		       "comedi: no check for data length of config insn id "
7420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "%i is implemented.\n"
7430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Add a check to %s in %s.\n"
7440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Assuming n=%i is correct.\n", data[0], __func__,
7450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       __FILE__, insn->n);
746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
7530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file)
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
75534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
820790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
8420fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, 1, &insn->chanspec);
843476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
861476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
862476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
894476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
89920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSN
90020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
90220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
90320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to insn
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
90520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
90620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		struct comedi_insn struct at arg
90720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
90920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
91020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
91271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
91490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn insn;
915790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
918790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
92490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
9330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (copy_from_user
9340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (data, insn.data, insn.n * sizeof(unsigned int))) {
935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
9430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (copy_to_user
9440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (insn.data, data, insn.n * sizeof(unsigned int))) {
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
951476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
952476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMD
959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command ioctl
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
97271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
974ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
97534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
976d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
980ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
984476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1035476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1040476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1048476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
10550fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman	ret = comedi_check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1056476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1066476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
1069ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1087476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1088476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1089476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1098476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
111971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file)
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1121ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
112234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist_saver = NULL;
1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1127ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1131476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1162476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1170476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
11770fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
1178476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1188476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1191ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1196476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1197476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
12180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
122234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12285f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1229476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1231476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
12335f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
12620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
12630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
126534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
13040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
130634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
13410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
134334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
136434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area)
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1378d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
137971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
13900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.close = comedi_unmap,
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1396476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1397476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
139871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1399d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
140534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1413476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1415476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1417476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
14470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    page_to_pfn(virt_to_page
14480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						(async->buf_page_list
14490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						 [i].virt_addr)), PAGE_SIZE,
14500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PAGE_SHARED)) {
1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1463476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
14680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait)
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1472476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1473476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
147471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
147534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
147634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
1477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1490476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1491476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1492476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1499476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1500476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1502476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1503476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1504476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1505476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
15156705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
151734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1518d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1522476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1523476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
152471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1558476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1561476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1569476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1586476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1596476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1613476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
16176705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
161934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1620d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1624476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1625476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
162671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1660476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1661476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1663476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1671476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1698476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1714476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1721476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
172734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1729d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1736476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1737476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1746476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1747476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
17480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev =
17490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dev_file_info ? dev_file_info->device : NULL;
1750979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1772a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1777a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
178456d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1790a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1791a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1806476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 0 && dev->open)
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->open(dev);
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1819476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1820476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
182171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
182234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1831476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1833476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1837476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1841476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1848476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1857476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1858476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1859476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
186071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
18660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.owner = THIS_MODULE,
18670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.unlocked_ioctl = comedi_unlocked_ioctl,
18680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.compat_ioctl = comedi_compat_ioctl,
18690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.open = comedi_open,
18700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.release = comedi_close,
18710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.read = comedi_read,
18720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.write = comedi_write,
18730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.mmap = comedi_mmap,
18740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.poll = comedi_poll,
18750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.fasync = comedi_fasync,
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1878476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1884476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
18851dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1894476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1895476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1897a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
1898a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1899a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
1900a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1901a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1902a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
1903a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
1904a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1905a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
1906a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
1907a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1908a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
1909a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
1910a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1911a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
1912a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1913476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1914476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1917476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1925476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
19303fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_ERR "comedi: failed to create class");
1931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1933476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1940476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19411dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1944476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1948476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
1961476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
1963476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
197471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
19763fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
19773fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	       dev->driver->driver_name, s);
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
197918736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_error);
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
198134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1983d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
1985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1987476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
1990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
19920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (s->
19930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
19940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     COMEDI_CB_OVERFLOW)) {
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2010fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			wake_up_interruptible(&async->wait_head);
20116705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_READ)
20120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
20136705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_WRITE)
20140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
202218736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_event);
2023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
202434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
2025476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   unsigned bits)
2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20295f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags &= ~mask;
2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->runflags |= (bits & mask);
20325f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
203418736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_set_subdevice_runflags);
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
203634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20415f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
20435f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
204618736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_get_subdevice_runflags);
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
204871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
205034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
206771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_init(struct comedi_device *dev)
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
206971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
207571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_cleanup(struct comedi_device *dev)
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2077476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2078476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
20890bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2091883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2094476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2095476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
209671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2097476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
21025f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2103476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2104476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
21095f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2110476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
21140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
211520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere
21160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: error: ran out of minor numbers for board device files.\n");
2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2121476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2123476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2125883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2126883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2127883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2131883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2132883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2133883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2134883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2135883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2139883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2140883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2141883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2142883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2143883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2147883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2148883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2149883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2150883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2151883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
21530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
21540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2155883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2156883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2157883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
216018736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_alloc_board_minor);
2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
21685f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
21715f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2173476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
217471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2175476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2176476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2177476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2178476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
218618736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_free_board_minor);
2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2188883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev,
2189883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				 struct comedi_subdevice *s)
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
21930bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2195883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2198476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2199476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
22035f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
22044c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2205476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
22105f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2211476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
22130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: error: ran out of minor numbers for board device files.\n");
2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2219476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2220476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2221476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2224883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2225883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2226883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2230883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2231883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2232883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2233883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2234883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2238883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2239883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2240883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2241883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2242883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2246883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2247883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2248883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2249883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2250883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
22520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi: failed to create sysfs attribute file \"%s\".\n",
22530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2254883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2255883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2256883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
226034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2265476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2266476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2267476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2268476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
22735f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
22765f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2278476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
22915f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
22935f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
229618736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_get_device_file_info);
2297883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2298883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
2299883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
2300883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size)
2301883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2302883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2303883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2304883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (new_size > async->max_bufsize)
2305883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EPERM;
2306883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2307883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->busy) {
2308883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is busy, cannot resize buffer\n");
2309883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2310883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2311883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (async->mmap_count) {
2312883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2314883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2315883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2316883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (!async->prealloc_buf)
2317883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2318883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2319883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	/* make sure buffer is an integral number of pages
23200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 * (we round up) */
2321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2323883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = comedi_buf_alloc(dev, s, new_size);
2324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2325883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2326883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2327883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->buf_change) {
2328883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = s->buf_change(dev, s, new_size);
2329883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
2330883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
2331883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2332883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2334b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return 0;
2336883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2337883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */
2339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024;
2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev,
2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				       struct device_attribute *attr, char *buf)
2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2347883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2348883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2354883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async) {
2355883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = read_subdevice->async->max_bufsize /
23560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
23580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2363883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2364883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev,
2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					const char *buf, size_t count)
2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2370883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2371883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2373883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2374883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
23760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2377883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
23780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
23790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2380883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2381883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2382883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2383883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2384883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2385883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2389883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	read_subdevice->async->max_bufsize = new_max_size;
2390883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2393883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2395883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = {
2396883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
23970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_read_buffer_kb",
23980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_read_buffer_kb,
2400883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_read_buffer_kb
2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2402883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2403883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev,
2404883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				   struct device_attribute *attr, char *buf)
2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2406883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2407883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2408883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2409883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
24140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
24150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    read_subdevice->async) {
2416883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
24170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2420883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2421883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2422883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2423883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev,
2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr,
2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    const char *buf, size_t count)
2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2432883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2433883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2439883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
24410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2443883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2446883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2447883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, read_subdevice,
2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     read_subdevice->async, new_size);
2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2454883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2458883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = {
2461883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "read_buffer_kb",
24630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_read_buffer_kb,
2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_read_buffer_kb
2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2468883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev,
2469883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					char *buf)
2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
24760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2481883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2482883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = write_subdevice->async->max_bufsize /
24830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2484883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2486883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2488883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2489883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2490883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2491883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev,
2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 struct device_attribute *attr,
2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 const char *buf, size_t count)
2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2497883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
24990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2504883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
25060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2507883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2509883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2510883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2511883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	write_subdevice->async->max_bufsize = new_max_size;
2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = {
2523883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_write_buffer_kb",
25250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_write_buffer_kb,
2527883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_write_buffer_kb
2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2529883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2530883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev,
2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr, char *buf)
2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2542883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2543883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
25440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2548883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2549883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2550883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2551883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2552883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev,
2553883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     struct device_attribute *attr,
2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     const char *buf, size_t count)
2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2559883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2566883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
25680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2570883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2571883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2573883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, write_subdevice,
25790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     write_subdevice->async, new_size);
2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2581883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2585883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2587883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = {
2588883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "write_buffer_kb",
25900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2591883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_write_buffer_kb,
2592883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_write_buffer_kb
2593883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2594