comedi_fops.c revision 4772c018e35b6a21e8a8bde54568b59998540a16
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
646a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottint 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,
8692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_bufinfo __user *arg);
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
1040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralextern 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,
17292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				      (struct comedi_bufinfo __user *)arg);
173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
18492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
18792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
18892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				      file);
189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
19192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_insnlist_ioctl(dev,
19292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       (struct comedi_insnlist __user *)arg,
19392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       file);
194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
19692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
19792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				   file);
198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
207476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
2250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
22692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_devconfig __user *arg)
227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2280707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	struct comedi_devconfig it;
229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
239476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2470707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
253476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
264476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
269476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
273476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
279476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
280476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
30692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufconfig_ioctl(struct comedi_device *dev,
30792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_bufconfig __user *arg)
308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
309be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	struct comedi_bufconfig bc;
310d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
31134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
312883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval = 0;
313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
314be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = resize_async_buffer(dev, s, async, bc.size);
339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
346476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
347be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
36892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_devinfo __user *arg,
36992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct file *file)
370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
371063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	struct comedi_devinfo devinfo;
372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
374476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
37534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
376476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
37734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
378476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
388476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
390476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
392476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
393476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
395476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
398063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
41992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_subdinfo __user *arg, void *file)
420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
422bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton	struct comedi_subdinfo *tmp, *us;
42334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
4250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	tmp =
4260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
4270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
447476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
479bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
5000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
50192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_chaninfo __user *arg)
502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
50334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
504a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	struct comedi_chaninfo it;
505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
506a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
517790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
538476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
541476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
542476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
5430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 s->n_chan * sizeof(unsigned int)))
544476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
545476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
56592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufinfo_ioctl(struct comedi_device *dev,
56692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_bufinfo __user *arg)
567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
5689aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	struct comedi_bufinfo bi;
56934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
570d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5729aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
5874772c018e35b6a21e8a8bde54568b59998540a16Ian Abbott		bi.bytes_read = 0;
5884772c018e35b6a21e8a8bde54568b59998540a16Ian Abbott		bi.bytes_written = 0;
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
597476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
598476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
605476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
614476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
6159aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
6220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file);
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
62420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSNLIST
62520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
62720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
62820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to sync cmd structure
629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
63020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
63120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		sync cmd struct at arg
63220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		instruction list
63320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
63520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
63620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
64092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev,
64192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_insnlist __user *arg, void *file)
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
643da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	struct comedi_insnlist insnlist;
64490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn *insns = NULL;
645790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
649da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
652790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	insns =
6600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
66890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
682790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
693790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
703476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
704476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
705476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn,
7130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    unsigned int *data)
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
715476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
716476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
7600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* by default we allow the insn since we don't have checks for
7610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 * all possible cases yet */
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
7633fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_WARNING
7643fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		       "comedi: no check for data length of config insn id "
7650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "%i is implemented.\n"
7660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Add a check to %s in %s.\n"
7670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Assuming n=%i is correct.\n", data[0], __func__,
7680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       __FILE__, insn->n);
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
7760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file)
777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
77834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
843790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
8650fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, 1, &insn->chanspec);
866476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
884476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
885476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
917476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
92220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSN
92320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
92520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
92620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to insn
927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
92820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
92920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		struct comedi_insn struct at arg
93020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
93220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
93320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
93592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev,
93692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			 struct comedi_insn __user *arg, void *file)
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
93890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn insn;
939790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
942790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
94890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
95721fe2eea6381845956322e63e441f351774de7f9Mark		if (copy_from_user(data,
95821fe2eea6381845956322e63e441f351774de7f9Mark				   insn.data,
95921fe2eea6381845956322e63e441f351774de7f9Mark				   insn.n * sizeof(unsigned int))) {
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
96821fe2eea6381845956322e63e441f351774de7f9Mark		if (copy_to_user(insn.data,
96921fe2eea6381845956322e63e441f351774de7f9Mark				 data,
97021fe2eea6381845956322e63e441f351774de7f9Mark				 insn.n * sizeof(unsigned int))) {
971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
977476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
978476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
983181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartmanstatic void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
984181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman					  unsigned mask, unsigned bits)
985181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman{
986181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	unsigned long flags;
987181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman
988181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
989181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	s->runflags &= ~mask;
990181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	s->runflags |= (bits & mask);
991181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
992181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman}
993181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman
99492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev,
99592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			struct comedi_cmd __user *cmd, void *file)
996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
997ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
99834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
999d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
100192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	unsigned int __user *chanlist_saver = NULL;
1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
100392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1007476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1058476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1063476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1071476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
107821fe2eea6381845956322e63e441f351774de7f9Mark	ret = comedi_check_chanlist(s,
107921fe2eea6381845956322e63e441f351774de7f9Mark				    async->cmd.chanlist_len,
108021fe2eea6381845956322e63e441f351774de7f9Mark				    async->cmd.chanlist);
1081476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1091476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
109492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1112476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1113476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1114476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1123476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
114492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev,
114592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_cmd __user *arg, void *file)
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1147ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
114834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
115192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	unsigned int __user *chanlist_saver = NULL;
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1153ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1157476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1188476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1196476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
12030fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
1204476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1214476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1217ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1223476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
12440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
124834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12545f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1255476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1257476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
12595f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
12880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
12890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
129134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
13300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
133234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
13670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
136934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
139034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
140292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_unmap(struct vm_area_struct *area)
1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1404d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
140571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
14160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.close = comedi_unmap,
1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1422476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1423476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
142471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1425d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
143134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1439476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1441476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1443476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
14730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    page_to_pfn(virt_to_page
14740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						(async->buf_page_list
14750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						 [i].virt_addr)), PAGE_SIZE,
14760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PAGE_SHARED)) {
1477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1489476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
14940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait)
1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1498476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1499476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
150071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
150134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
150234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1516476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1517476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1518476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1528476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1529476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1530476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1531476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
154092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_write(struct file *file, const char __user *buf,
154192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    size_t nbytes, loff_t *offset)
1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
154334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1544d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1548476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1549476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
155071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1581d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott		if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1582d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			if (count == 0) {
1583d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				if (comedi_get_subdevice_runflags(s) &
1584d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					SRF_ERROR) {
1585d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					retval = -EPIPE;
1586d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				} else {
1587d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					retval = 0;
1588d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				}
1589d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				do_become_nonbusy(dev, s);
1590d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			}
1591d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			break;
1592d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott		}
1593d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott
1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1597476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1600476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1615476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1625476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1642476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
164592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
16466705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
164834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1649d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1653476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1654476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
165571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1689476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1690476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1692476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1700476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1727476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1743476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1750476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
175634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1758d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1765476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1766476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1775476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1776476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
17770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev =
17780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dev_file_info ? dev_file_info->device : NULL;
1779979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1801a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1806a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
181356d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1819a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1820a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1835476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 0 && dev->open)
1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->open(dev);
1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1848476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1849476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
185071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
185134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1860476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1862476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1866476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1870476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1877476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1886476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1887476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1888476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
188971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
18950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.owner = THIS_MODULE,
18960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.unlocked_ioctl = comedi_unlocked_ioctl,
18970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.compat_ioctl = comedi_compat_ioctl,
18980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.open = comedi_open,
18990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.release = comedi_close,
19000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.read = comedi_read,
19010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.write = comedi_write,
19020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.mmap = comedi_mmap,
19030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.poll = comedi_poll,
19040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.fasync = comedi_fasync,
1905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1907476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1913476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
19141dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1923476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1924476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1926a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
1927a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1928a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
1929a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1930a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1931a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
1932a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
1933a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1934a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
1935a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
1936a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1937a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
1938a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
1939a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1940a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
1941a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1942476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1943476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1946476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1954476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
19593fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_ERR "comedi: failed to create class");
1960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1962476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1969476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19701dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1973476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1977476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
1990476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
1992476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
200371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
20053fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
20063fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	       dev->driver->driver_name, s);
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
200818736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_error);
2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
201034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2012d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2016476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (s->
20220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
20230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     COMEDI_CB_OVERFLOW)) {
2024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
2025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2039fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			wake_up_interruptible(&async->wait_head);
20406705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_READ)
20410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
20426705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_WRITE)
20430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
205118736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_event);
2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
205334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20585f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
20605f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
206318736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_get_subdevice_runflags);
2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
206571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
206734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
208492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_init(struct comedi_device *dev)
2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
208671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
209292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_cleanup(struct comedi_device *dev)
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2094476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2095476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
21060bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2108883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2111476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2112476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
211371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2114476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
21195f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2120476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2121476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
21265f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2127476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
21310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
213221fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: error: "
213321fe2eea6381845956322e63e441f351774de7f9Mark		       "ran out of minor numbers for board device files.\n");
2134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2138476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2139476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2140476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2142883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2143883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2144883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
214621fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
214721fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2149883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2150883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2151883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2152883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2153883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
215521fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
215621fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2158883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2159883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2160883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2161883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2162883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
216421fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
216521fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2167883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2168883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2169883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2170883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2171883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
217321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
217421fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2176883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2177883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2178883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
21885f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
21915f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2193476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
219471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2195476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2196476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2197476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2198476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2207883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev,
2208883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				 struct comedi_subdevice *s)
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
22120bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2214883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2217476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2218476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
22225f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
22234c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2224476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
22295f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2230476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
22320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
223321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: error: "
223421fe2eea6381845956322e63e441f351774de7f9Mark		       "ran out of minor numbers for board device files.\n");
2235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2239476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2241476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2242476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2244883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2245883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2246883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
224821fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
224921fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2251883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2252883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2253883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2254883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2255883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
225721fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
225821fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2260883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2261883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2262883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2263883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2264883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
226621fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
226721fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2269883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2270883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2271883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2272883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2273883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
227521fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
227621fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2278883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2279883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2280883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
228434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2289476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2290476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2291476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2292476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
22975f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
23005f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2302476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
23155f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
23175f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
232018736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_get_device_file_info);
2321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
2323883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
2324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size)
2325883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2326883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2327883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2328883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (new_size > async->max_bufsize)
2329883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EPERM;
2330883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2331883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->busy) {
2332883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is busy, cannot resize buffer\n");
2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2334883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (async->mmap_count) {
2336883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2337883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (!async->prealloc_buf)
2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	/* make sure buffer is an integral number of pages
23440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 * (we round up) */
2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2347883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = comedi_buf_alloc(dev, s, new_size);
2348883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->buf_change) {
2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = s->buf_change(dev, s, new_size);
2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
2354883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
2355883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2356883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2358b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return 0;
2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */
2363883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2364883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024;
2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev,
2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				       struct device_attribute *attr, char *buf)
2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2370883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2371883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2372883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2374883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2376883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
2377883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2378883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async) {
2379883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = read_subdevice->async->max_bufsize /
23800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2381883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
23820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2383883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2384883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2385883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev,
2389883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2390883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					const char *buf, size_t count)
2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2393883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2395883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2397883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2398883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
24030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2404883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2406883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2407883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2408883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2409883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	read_subdevice->async->max_bufsize = new_max_size;
2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2415883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2416883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2417883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2419883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = {
2420883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_read_buffer_kb",
24220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2423883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_read_buffer_kb,
2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_read_buffer_kb
2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev,
2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				   struct device_attribute *attr, char *buf)
2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2432883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2433883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
24380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
24390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    read_subdevice->async) {
2440883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
24410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2446883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2447883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev,
2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr,
2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    const char *buf, size_t count)
2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2454883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2461883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2463883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
24650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2468883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2469883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, read_subdevice,
2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     read_subdevice->async, new_size);
2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2481883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2482883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2483883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2484883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = {
2485883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "read_buffer_kb",
24870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2488883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_read_buffer_kb,
2489883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_read_buffer_kb
2490883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2491883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev,
2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					char *buf)
2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2497883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2503883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2504883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2505883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2506883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = write_subdevice->async->max_bufsize /
25070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2510883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2511883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev,
2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 struct device_attribute *attr,
2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 const char *buf, size_t count)
2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
25300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	write_subdevice->async->max_bufsize = new_max_size;
2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2542883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2543883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2544883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2546883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = {
2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_write_buffer_kb",
25490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2550883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_write_buffer_kb,
2551883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_write_buffer_kb
2552883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2553883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev,
2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr, char *buf)
2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2559883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2565883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2566883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2567883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
25680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2571883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2573883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev,
2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     struct device_attribute *attr,
2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     const char *buf, size_t count)
2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2581883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2587883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2588883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2590883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
25920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2593883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2594883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2595883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2596883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2597883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2598883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2599883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2600883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2601883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2602883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, write_subdevice,
26030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     write_subdevice->async, new_size);
2604883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2605883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2606883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2607883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2608883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2609883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2610883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2611883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = {
2612883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
26130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "write_buffer_kb",
26140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2615883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_write_buffer_kb,
2616883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_write_buffer_kb
2617883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2618