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
52242e7ad91a067243d7ab63b6a25ed2e085733446Greg Kroah-Hartman#include "internal.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
6490ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellbool comedi_autoconfig = 1;
656a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottmodule_param(comedi_autoconfig, bool, 0444);
666a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbott
6792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int 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,
7592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_devconfig __user *arg);
7692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufconfig_ioctl(struct comedi_device *dev,
7792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_bufconfig __user *arg);
780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
7992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_devinfo __user *arg,
8092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct file *file);
810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
8292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_subdinfo __user *arg, void *file);
830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
8492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_chaninfo __user *arg);
8592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufinfo_ioctl(struct comedi_device *dev,
8653fa827e295d8b09a2446b3126577244644d256dIan Abbott			    struct comedi_bufinfo __user *arg, void *file);
8792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev,
8892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			struct comedi_cmd __user *arg, void *file);
890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
9592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev,
9692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_cmd __user *arg, void *file);
9792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev,
9892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_insnlist __user *arg, void *file);
9992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev,
10092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			 struct comedi_insn __user *arg, void *file);
1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
1020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
10371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton
104f5283a4bb8f5ef274e9de58c751edb2a2d66bef4Mark Pearsonstatic void do_become_nonbusy(struct comedi_device *dev,
1050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			      struct comedi_subdevice *s);
10634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on);
109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
11071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev);
111883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
112883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
113883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size);
114883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
115883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* declarations for sysfs attribute files */
116883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb;
117883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb;
118883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb;
119883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb;
120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				  unsigned long arg)
123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
125476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
126476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
12771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int rc;
129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
13053b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	if (dev_file_info == NULL || dev_file_info->device == NULL)
13153b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess		return -ENODEV;
13253b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess	dev = dev_file_info->device;
13353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess
134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* Device config is special, because it must work on
137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * an unconfigured device. */
138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cmd == COMEDI_DEVCONFIG) {
13992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_devconfig_ioctl(dev,
14092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman					(struct comedi_devconfig __user *)arg);
141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENODEV;
147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (cmd) {
151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFCONFIG:
15292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_bufconfig_ioctl(dev,
15392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman					(struct comedi_bufconfig __user *)arg);
154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_DEVINFO:
15692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
15792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				      file);
158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_SUBDINFO:
16092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_subdinfo_ioctl(dev,
16192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       (struct comedi_subdinfo __user *)arg,
16292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       file);
163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CHANINFO:
16592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_chaninfo_ioctl(dev, (void __user *)arg);
166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_RANGEINFO:
16892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_BUFINFO:
17192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_bufinfo_ioctl(dev,
17253fa827e295d8b09a2446b3126577244644d256dIan Abbott				      (struct comedi_bufinfo __user *)arg,
17353fa827e295d8b09a2446b3126577244644d256dIan Abbott				      file);
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
18592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
18892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
18992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				      file);
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
19292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_insnlist_ioctl(dev,
19392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       (struct comedi_insnlist __user *)arg,
19492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       file);
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
19792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
19892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				   file);
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
208476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
2260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
22792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_devconfig __user *arg)
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2290707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	struct comedi_devconfig it;
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2480707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
254476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
265476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
270476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
274476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
280476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
281476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
283d026b7150e38a1764d83fc57b6e4448d5e278eafJulia Lawall			ret = -ENOSYS;
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
30792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufconfig_ioctl(struct comedi_device *dev,
30892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_bufconfig __user *arg)
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
310be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	struct comedi_bufconfig bc;
311d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
31234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval = 0;
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
315be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = resize_async_buffer(dev, s, async, bc.size);
340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
347476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
348be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
36992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_devinfo __user *arg,
37092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct file *file)
371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
372063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	struct comedi_devinfo devinfo;
373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
374476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
375476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
37634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
377476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
37834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
379476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
386819cbb120eaec7e014e5abd029260db1ca8c5735Vasiliy Kulikov	strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
387819cbb120eaec7e014e5abd029260db1ca8c5735Vasiliy Kulikov	strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
389476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
391476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
393476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
394476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
396476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
399063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
42092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_subdinfo __user *arg, void *file)
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
423bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton	struct comedi_subdinfo *tmp, *us;
42434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
4260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	tmp =
4270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
4280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
448476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
480bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
5010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
50292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_chaninfo __user *arg)
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
50434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
505a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	struct comedi_chaninfo it;
506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
507a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
518790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
539476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
54081604d43ade6abd316444f99ddb633f2e5a3f3ebVasiliy Kulikov			if (put_user(x, it.rangelist + i))
54181604d43ade6abd316444f99ddb633f2e5a3f3ebVasiliy Kulikov				return -EFAULT;
542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
543476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
544476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
5450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 s->n_chan * sizeof(unsigned int)))
546476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
547476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
56792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufinfo_ioctl(struct comedi_device *dev,
56853fa827e295d8b09a2446b3126577244644d256dIan Abbott			    struct comedi_bufinfo __user *arg, void *file)
569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
5709aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	struct comedi_bufinfo bi;
57134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
572d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5749aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
58153fa827e295d8b09a2446b3126577244644d256dIan Abbott
58253fa827e295d8b09a2446b3126577244644d256dIan Abbott	if (s->lock && s->lock != file)
58353fa827e295d8b09a2446b3126577244644d256dIan Abbott		return -EACCES;
58453fa827e295d8b09a2446b3126577244644d256dIan Abbott
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
5934772c018e35b6a21e8a8bde54568b59998540a16Ian Abbott		bi.bytes_read = 0;
5944772c018e35b6a21e8a8bde54568b59998540a16Ian Abbott		bi.bytes_written = 0;
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
59753fa827e295d8b09a2446b3126577244644d256dIan Abbott	if (!s->busy) {
59853fa827e295d8b09a2446b3126577244644d256dIan Abbott		bi.bytes_read = 0;
59953fa827e295d8b09a2446b3126577244644d256dIan Abbott		bi.bytes_written = 0;
60053fa827e295d8b09a2446b3126577244644d256dIan Abbott		goto copyback_position;
60153fa827e295d8b09a2446b3126577244644d256dIan Abbott	}
60253fa827e295d8b09a2446b3126577244644d256dIan Abbott	if (s->busy != file)
60353fa827e295d8b09a2446b3126577244644d256dIan Abbott		return -EACCES;
604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
610476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
611476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
618476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
62253fa827e295d8b09a2446b3126577244644d256dIan Abbottcopyback_position:
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
628476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
6299aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
6360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file);
637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
63820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSNLIST
63920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
64120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
64220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to sync cmd structure
643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
64420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
64520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		sync cmd struct at arg
64620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		instruction list
64720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
64920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
65020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
65492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev,
65592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_insnlist __user *arg, void *file)
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
657da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	struct comedi_insnlist insnlist;
65890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn *insns = NULL;
659790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
663da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
666790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	insns =
674dfd8ee92a9192d78aa38cf8699df3630a7c88c85Xi Wang	    kcalloc(insnlist.n_insns, sizeof(struct comedi_insn), GFP_KERNEL);
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
68290035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
696790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
707790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
717476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
718476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
719476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn,
7270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    unsigned int *data)
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
729476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
730476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
7740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* by default we allow the insn since we don't have checks for
7750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 * all possible cases yet */
776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
7773fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_WARNING
7783fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		       "comedi: no check for data length of config insn id "
7790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "%i is implemented.\n"
7800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Add a check to %s in %s.\n"
7810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Assuming n=%i is correct.\n", data[0], __func__,
7820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       __FILE__, insn->n);
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
7900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file)
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
79234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
857790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
8790fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, 1, &insn->chanspec);
880476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
898476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
899476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
9132f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott			} else {
9142f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				/* Most drivers ignore the base channel in
9152f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				 * insn->chanspec.  Fix this here if
9162f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				 * the subdevice has <= 32 channels.  */
9172f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				unsigned int shift;
9182f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				unsigned int orig_mask;
9192f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott
9202f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				orig_mask = data[0];
9212f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				if (s->n_chan <= 32) {
9222f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott					shift = CR_CHAN(insn->chanspec);
9232f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott					if (shift > 0) {
9242f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott						insn->chanspec = 0;
9252f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott						data[0] <<= shift;
9262f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott						data[1] <<= shift;
9272f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott					}
9282f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				} else
9292f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott					shift = 0;
9302f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				ret = s->insn_bits(dev, s, insn, data);
9312f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				data[0] = orig_mask;
9322f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott				if (shift > 0)
9332f644ccfc5a3195290d12b8eedf18a37bba27d98Ian Abbott					data[1] >>= shift;
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
950476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
95520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSN
95620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
95820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
95920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to insn
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
96120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
96220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		struct comedi_insn struct at arg
96320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
96520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
96620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
96892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev,
96992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			 struct comedi_insn __user *arg, void *file)
970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
97190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn insn;
972790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
975790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
98190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
99021fe2eea6381845956322e63e441f351774de7f9Mark		if (copy_from_user(data,
99121fe2eea6381845956322e63e441f351774de7f9Mark				   insn.data,
99221fe2eea6381845956322e63e441f351774de7f9Mark				   insn.n * sizeof(unsigned int))) {
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
100121fe2eea6381845956322e63e441f351774de7f9Mark		if (copy_to_user(insn.data,
100221fe2eea6381845956322e63e441f351774de7f9Mark				 data,
100321fe2eea6381845956322e63e441f351774de7f9Mark				 insn.n * sizeof(unsigned int))) {
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1010476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
1011476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1016181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartmanstatic void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
1017181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman					  unsigned mask, unsigned bits)
1018181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman{
1019181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	unsigned long flags;
1020181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman
1021181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1022181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	s->runflags &= ~mask;
1023181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	s->runflags |= (bits & mask);
1024181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1025181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman}
1026181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman
102792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev,
102892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			struct comedi_cmd __user *cmd, void *file)
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1030ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
103134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1032d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
103492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	unsigned int __user *chanlist_saver = NULL;
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
103692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1040476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1091476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1096476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1104476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
111121fe2eea6381845956322e63e441f351774de7f9Mark	ret = comedi_check_chanlist(s,
111221fe2eea6381845956322e63e441f351774de7f9Mark				    async->cmd.chanlist_len,
111321fe2eea6381845956322e63e441f351774de7f9Mark				    async->cmd.chanlist);
1114476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1124476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
112792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1145476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1146476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1147476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1156476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
117792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev,
117892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_cmd __user *arg, void *file)
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1180ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
118134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
118492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	unsigned int __user *chanlist_saver = NULL;
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1186ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1190476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1221476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1229476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
12360fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
1237476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1247476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1250ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1255476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1256476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
12770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
128134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12875f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1288476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1290476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
12925f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1294c5274ab09747d0ef829f9b8f040756758e5de55cGreg Dietsche#if 0
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
13220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
132434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
13630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
136534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
14000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
140234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
142334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1435df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga
1436df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vagastatic void comedi_vm_open(struct vm_area_struct *area)
1437df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga{
1438df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	struct comedi_async *async;
1439df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	struct comedi_device *dev;
1440df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga
1441df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	async = area->vm_private_data;
1442df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	dev = async->subdevice->device;
1443df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga
1444df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	mutex_lock(&dev->mutex);
1445df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	async->mmap_count++;
1446df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	mutex_unlock(&dev->mutex);
1447df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga}
1448df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga
1449df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vagastatic void comedi_vm_close(struct vm_area_struct *area)
1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1451d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
145271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
1463df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	.open = comedi_vm_open,
1464df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821dFederico Vaga	.close = comedi_vm_close,
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1470d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
147634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
14773ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device_file_info *dev_file_info;
14783ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device *dev;
14793ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr
14803ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev_file_info = comedi_get_device_file_info(minor);
14813ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev_file_info == NULL)
148270fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
14833ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev = dev_file_info->device;
14843ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev == NULL)
148570fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1493476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1495476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1497476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
15270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    page_to_pfn(virt_to_page
15280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						(async->buf_page_list
15290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						 [i].virt_addr)), PAGE_SIZE,
15300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PAGE_SHARED)) {
1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1543476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
15480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait)
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
155234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
155334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
15543ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device_file_info *dev_file_info;
15553ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device *dev;
15563ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev_file_info = comedi_get_device_file_info(minor);
15573ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr
15583ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev_file_info == NULL)
155970fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
15603ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev = dev_file_info->device;
15613ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev == NULL)
156270fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1576476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1577476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1578476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1585476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1586476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1588476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1589476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1590476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1591476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
160092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_write(struct file *file, const char __user *buf,
160192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    size_t nbytes, loff_t *offset)
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
160334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1604d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
16083ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device_file_info *dev_file_info;
16093ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device *dev;
16103ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev_file_info = comedi_get_device_file_info(minor);
16113ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr
16123ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev_file_info == NULL)
161370fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
16143ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev = dev_file_info->device;
16153ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev == NULL)
161670fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1647d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott		if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1648d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			if (count == 0) {
1649d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				if (comedi_get_subdevice_runflags(s) &
1650d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					SRF_ERROR) {
1651d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					retval = -EPIPE;
1652d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				} else {
1653d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					retval = 0;
1654d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				}
1655d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				do_become_nonbusy(dev, s);
1656d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			}
1657d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			break;
1658d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott		}
1659d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott
1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1663476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1666476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
16766a9ce6b654e491981f6ef7e214cbd4f63e033848Federico Vaga			schedule();
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1681476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1691476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1708476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
171192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
17126705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
171434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1715d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
17193ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device_file_info *dev_file_info;
17203ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device *dev;
17213ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev_file_info = comedi_get_device_file_info(minor);
17223ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr
17233ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev_file_info == NULL)
172470fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
17253ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev = dev_file_info->device;
17263ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev == NULL)
172770fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1761476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1762476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1764476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1772476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
17836a9ce6b654e491981f6ef7e214cbd4f63e033848Federico Vaga			schedule();
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1799476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1815476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1822476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
182834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1830d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1837476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1838476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1847476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1848476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
18490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev =
18500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dev_file_info ? dev_file_info->device : NULL;
1851979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1873a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1878a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
188556d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1891a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1892a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
19073c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott	if (dev->attached && dev->use_count == 0 && dev->open) {
19083c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		int rc = dev->open(dev);
19093c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		if (rc < 0) {
19103c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			module_put(dev->driver->module);
19113c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			module_put(THIS_MODULE);
19123c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			mutex_unlock(&dev->mutex);
19133c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			return rc;
19143c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		}
19153c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott	}
1916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
192734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
19293ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device_file_info *dev_file_info;
19303ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device *dev;
19313ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev_file_info = comedi_get_device_file_info(minor);
19323ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr
19333ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev_file_info == NULL)
193470fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
19353ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev = dev_file_info->device;
19363ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev == NULL)
193770fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1945476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1947476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1951476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1955476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1962476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
19713ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device_file_info *dev_file_info;
19723ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	struct comedi_device *dev;
19733ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev_file_info = comedi_get_device_file_info(minor);
1974476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
19753ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev_file_info == NULL)
197670fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
19773ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	dev = dev_file_info->device;
19783ffab428f40849ed5f21bcfd7285bdef7902f9caBernd Porr	if (dev == NULL)
197970fe742c94d4d5e7763c3f864f13c0e907ac3d48Florian Schmaus		return -ENODEV;
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
19850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.owner = THIS_MODULE,
19860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.unlocked_ioctl = comedi_unlocked_ioctl,
19870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.compat_ioctl = comedi_compat_ioctl,
19880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.open = comedi_open,
19890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.release = comedi_close,
19900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.read = comedi_read,
19910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.write = comedi_write,
19920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.mmap = comedi_mmap,
19930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.poll = comedi_poll,
19940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.fasync = comedi_fasync,
19956038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek = noop_llseek,
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1998476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2004476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
20051dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2014476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
2015476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2017a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
2018a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
2019a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
2020a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
2021a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
2022a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
2023a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
2024a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
2025a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
2026a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
2027a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
2028a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
2029a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
2030a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
2031a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
2032a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
2033476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
2034476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2037476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
2041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
2043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2045476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
20503fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_ERR "comedi: failed to create class");
2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2053476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2060476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
20611dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
2064476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2068476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
2081476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
2083476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
209471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
20963fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
20973fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	       dev->driver->driver_name, s);
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
209918736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_error);
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
210134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2103d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
2104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2107476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
2111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
21120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (s->
21130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
21140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     COMEDI_CB_OVERFLOW)) {
2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
211725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* remember if an error event has occurred, so an error
2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
2119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2130fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			wake_up_interruptible(&async->wait_head);
21316705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_READ)
21320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
21336705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_WRITE)
21340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
214218736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_event);
2143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
214434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
21495f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
21515f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
215418736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_get_subdevice_runflags);
2155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
215671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
215834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
217592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_init(struct comedi_device *dev)
2176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
217771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
218392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_cleanup(struct comedi_device *dev)
2184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2185476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2186476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
21970bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2199883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2202476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2203476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
220471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2205476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
22105f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2211476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2212476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
22175f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2218476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
22220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
222321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: error: "
222421fe2eea6381845956322e63e441f351774de7f9Mark		       "ran out of minor numbers for board device files.\n");
2225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
22280435f9337f051db77b4eaf02eee83e7a29f3474aPavel Roskin	csdev = device_create(comedi_class, hardware_device,
22290435f9337f051db77b4eaf02eee83e7a29f3474aPavel Roskin			      MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2230476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2232883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2233883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2234883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
223621fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
223721fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2239883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2240883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2241883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2242883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2243883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
224521fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
224621fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2248883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2249883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2250883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2251883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2252883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
225421fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
225521fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2257883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2258883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2259883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2260883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2261883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
226321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
226421fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2266883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2267883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2268883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
22785f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
22815f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2283476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
228471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2285476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2286476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2287476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2288476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2297883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev,
2298883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				 struct comedi_subdevice *s)
2299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
23020bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2304883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2307476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2308476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
23125f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
23134c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2314476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
23195f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2320476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
23220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
232321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: error: "
232421fe2eea6381845956322e63e441f351774de7f9Mark		       "ran out of minor numbers for board device files.\n");
2325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
23280435f9337f051db77b4eaf02eee83e7a29f3474aPavel Roskin	csdev = device_create(comedi_class, dev->class_dev,
23290435f9337f051db77b4eaf02eee83e7a29f3474aPavel Roskin			      MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
23300435f9337f051db77b4eaf02eee83e7a29f3474aPavel Roskin			      dev->minor, (int)(s - dev->subdevices));
2331476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2334883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
23360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
233721fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
233821fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
23390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
23450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
234621fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
234721fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
23480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
23540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
235521fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
235621fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
23570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2358883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
23630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
236421fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
236521fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
23660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
237334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2378476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2379476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2380476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2381476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
23865f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
23895f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2391476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
24045f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
24065f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
240918736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_get_device_file_info);
2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size)
2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2415883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2416883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2417883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (new_size > async->max_bufsize)
2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EPERM;
2419883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2420883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->busy) {
2421883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is busy, cannot resize buffer\n");
2422883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2423883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (async->mmap_count) {
2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (!async->prealloc_buf)
2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2432883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	/* make sure buffer is an integral number of pages
24330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 * (we round up) */
2434883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = comedi_buf_alloc(dev, s, new_size);
2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2438883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2439883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2440883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->buf_change) {
2441883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = s->buf_change(dev, s, new_size);
2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
2443883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2446883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2447b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return 0;
2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */
2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024;
2454883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev,
2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				       struct device_attribute *attr, char *buf)
2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2458883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2461883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2463883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async) {
2468883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = read_subdevice->async->max_bufsize /
24690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev,
2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					const char *buf, size_t count)
2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2481883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
24822e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	unsigned int new_max_size_kb;
2483c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	unsigned int new_max_size;
24842e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	int ret;
2485883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
24882e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	ret = kstrtouint(buf, 10, &new_max_size_kb);
24892e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	if (ret)
24902e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus		return ret;
2491c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2493c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	new_max_size = new_max_size_kb * bytes_per_kibi;
2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2497883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	read_subdevice->async->max_bufsize = new_max_size;
2503883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2504883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2505883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2506883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2507883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = {
2509883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_read_buffer_kb",
25110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_read_buffer_kb,
2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_read_buffer_kb
2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev,
2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				   struct device_attribute *attr, char *buf)
2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
25230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
25270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
25280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    read_subdevice->async) {
2529883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
25300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev,
2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr,
2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    const char *buf, size_t count)
2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2542883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
25432e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	unsigned int new_size_kb;
2544c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	unsigned int new_size;
2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
25462e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	int ret;
2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
25480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2549883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
25502e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	ret = kstrtouint(buf, 10, &new_size_kb);
25512e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	if (ret)
25522e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus		return ret;
2553c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2555c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	new_size = new_size_kb * bytes_per_kibi;
2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2559883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2561883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, read_subdevice,
2565883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     read_subdevice->async, new_size);
2566883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2567883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2568883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2570883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2571883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2573883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = {
2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "read_buffer_kb",
25760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_read_buffer_kb,
2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_read_buffer_kb
2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2581883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev,
2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					char *buf)
2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2585883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2587883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2588883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2590883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2591883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2592883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2593883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2594883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2595883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = write_subdevice->async->max_bufsize /
25960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2597883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2599883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2600883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2601883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2602883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2603883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2604883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev,
2605883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 struct device_attribute *attr,
2606883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 const char *buf, size_t count)
2607883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2608883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
26092e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	unsigned int new_max_size_kb;
2610c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	unsigned int new_max_size;
26112e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	int ret;
2612883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
26130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2614883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
26152e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	ret = kstrtouint(buf, 10, &new_max_size_kb);
26162e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	if (ret)
26172e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus		return ret;
2618c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
2619883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2620c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	new_max_size = new_max_size_kb * bytes_per_kibi;
2621883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2622883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2623883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2624883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2625883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2626883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2627883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2628883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2629883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	write_subdevice->async->max_bufsize = new_max_size;
2630883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2631883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2632883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2633883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2634883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2635883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = {
2636883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
26370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_write_buffer_kb",
26380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2639883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_write_buffer_kb,
2640883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_write_buffer_kb
2641883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2642883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2643883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev,
2644883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr, char *buf)
2645883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2646883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2647883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2648883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2649883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
26500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2651883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2652883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2653883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2654883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2655883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2656883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
26570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2658883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
26590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2660883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2661883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2662883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2663883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2664883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2665883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev,
2666883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     struct device_attribute *attr,
2667883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     const char *buf, size_t count)
2668883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2669883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
26702e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	unsigned int new_size_kb;
2671c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	unsigned int new_size;
2672883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
26732e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	int ret;
2674883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
26750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2676883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
26772e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	ret = kstrtouint(buf, 10, &new_size_kb);
26782e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus	if (ret)
26792e1c394fc398afb75d89c53f933149d33dc9e280Florian Schmaus		return ret;
2680c5018168a59b92ec3bd0f7b598e6d0d64d507e1eFlorian Schmaus	if (new_size_kb > (UINT_MAX / bytes_per_kibi))
2681883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
26820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2683883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2684883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2685883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2686883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2687883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2688883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2689883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2690883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2691883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, write_subdevice,
26920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     write_subdevice->async, new_size);
2693883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2694883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2695883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2696883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2697883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2698883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2699883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2700883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = {
2701883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
27020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "write_buffer_kb",
27030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2704883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_write_buffer_kb,
2705883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_write_buffer_kb
2706883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2707