comedi_fops.c revision 3c17ba0743d75f9888d905ddf9f8551c7dd36493
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,
8653fa827e295d8b09a2446b3126577244644d256dIan Abbott			    struct comedi_bufinfo __user *arg, void *file);
8792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev,
8892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			struct comedi_cmd __user *arg, void *file);
890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file);
9592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev,
9692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_cmd __user *arg, void *file);
9792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev,
9892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_insnlist __user *arg, void *file);
9992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev,
10092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			 struct comedi_insn __user *arg, void *file);
1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
1020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file);
10371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton
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,
17253fa827e295d8b09a2446b3126577244644d256dIan Abbott				      (struct comedi_bufinfo __user *)arg,
17353fa827e295d8b09a2446b3126577244644d256dIan Abbott				      file);
174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_LOCK:
176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_lock_ioctl(dev, arg, file);
177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_UNLOCK:
179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_unlock_ioctl(dev, arg, file);
180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CANCEL:
182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_cancel_ioctl(dev, arg, file);
183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMD:
18592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_CMDTEST:
18892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
18992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				      file);
190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSNLIST:
19292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_insnlist_ioctl(dev,
19392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       (struct comedi_insnlist __user *)arg,
19492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				       file);
195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_INSN:
19792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
19892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman				   file);
199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case COMEDI_POLL:
201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = do_poll_ioctl(dev, arg, file);
202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		rc = -ENOTTY;
205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
208476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return rc;
211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVCONFIG
215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device config ioctl
216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devconfig structure
219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devconfig structure at arg
222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
2260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev,
22792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_devconfig __user *arg)
228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2290707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	struct comedi_devconfig it;
230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret;
231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned char *aux_data = NULL;
232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int aux_len;
233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!capable(CAP_SYS_ADMIN))
235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EPERM;
236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg == NULL) {
238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (is_device_busy(dev))
239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EBUSY;
240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev->attached) {
241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			struct module *driver_module = dev->driver->module;
242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(driver_module);
244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2480707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	it.board_name[COMEDI_NAMELEN - 1] = 0;
252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (comedi_aux_data(it.options, 0) &&
254476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int bit_shift;
256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (aux_len < 0)
258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		aux_data = vmalloc(aux_len);
261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!aux_data)
262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOMEM;
263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(aux_data,
265476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   comedi_aux_data(it.options, 0), aux_len)) {
266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			vfree(aux_data);
267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
270476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    (unsigned long)aux_data;
271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (sizeof(void *) > sizeof(int)) {
272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			bit_shift = sizeof(int) * 8;
273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
274476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ((unsigned long)aux_data) >> bit_shift;
275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else
276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = comedi_device_attach(dev, &it);
280476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret == 0) {
281476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (!try_module_get(dev->driver->module)) {
282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_detach(dev);
283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (aux_data)
288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		vfree(aux_data);
289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_BUFCONFIG
295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	buffer configuration ioctl
296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to bufconfig structure
299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bufconfig at arg
302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified bufconfig at arg
305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
30792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufconfig_ioctl(struct comedi_device *dev,
30892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			      struct comedi_bufconfig __user *arg)
309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
310be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	struct comedi_bufconfig bc;
311d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
31234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval = 0;
314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
315be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bc.subdevice;
322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.size = 0;
327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bc.maximum_size = 0;
328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.maximum_size) {
332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!capable(CAP_SYS_ADMIN))
333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EPERM;
334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->max_bufsize = bc.maximum_size;
336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bc.size) {
339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = resize_async_buffer(dev, s, async, bc.size);
340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.size = async->prealloc_bufsz;
345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bc.maximum_size = async->max_bufsize;
346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
347476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
348be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_DEVINFO
356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	device info ioctl
357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to devinfo structure
360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo structure
366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
3680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev,
36992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_devinfo __user *arg,
37092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct file *file)
371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
372063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	struct comedi_devinfo devinfo;
373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
374476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
375476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
37634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev =
377476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_read_subdevice(dev_file_info);
37834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev =
379476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_write_subdevice(dev_file_info);
380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memset(&devinfo, 0, sizeof(devinfo));
382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill devinfo structure */
384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.version_code = COMEDI_VERSION_CODE;
385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	devinfo.n_subdevs = dev->n_subdevices;
386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
389476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (read_subdev)
390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = read_subdev - dev->subdevices;
391476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.read_subdevice = -1;
393476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
394476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (write_subdev)
395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = write_subdev - dev->subdevices;
396476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		devinfo.write_subdevice = -1;
398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
399063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_SUBDINFO
407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to array of subdevice info structures
411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		array of subdevice info structures at arg
417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
4190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev,
42092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_subdinfo __user *arg, void *file)
421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret, i;
423bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton	struct comedi_subdinfo *tmp, *us;
42434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
4260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	tmp =
4270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
4280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!tmp)
430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* fill subdinfo structs */
433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us = tmp + i;
436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->type = s->type;
438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->n_chan = s->n_chan;
439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->subd_flags = s->subdev_flags;
440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RUNNING;
442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5		/* backwards compatibility */
443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->timer_type = TIMER_nanosec;
444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->len_chanlist = s->len_chanlist;
445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->maxdata = s->maxdata;
446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table) {
447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type =
448476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (i << 24) | (0 << 16) | (s->range_table->length);
449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->range_type = 0;	/* XXX */
451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->flags = s->flags;
453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY;
456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy == file)
457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_BUSY_OWNER;
458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock)
459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCKED;
460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock == file)
461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_LOCK_OWNER;
462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->maxdata && s->maxdata_list)
463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_MAXDATA;
464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->flaglist)
465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_FLAGS;
466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->range_table_list)
467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_RANGETYPE;
468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->do_cmd)
469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->subd_flags |= SDF_CMD;
470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->insn_bits != &insn_inval)
472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_SUPPORTED;
473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		else
474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			us->insn_bits_support = COMEDI_UNSUPPORTED;
475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		us->settling_time_0 = s->settling_time_0;
477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = copy_to_user(arg, tmp,
480bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(tmp);
483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret ? -EFAULT : 0;
485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CHANINFO
489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	subdevice info ioctl
490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to chaninfo structure
493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chaninfo structure at arg
496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		arrays at elements of chaninfo structure
499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
5010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev,
50292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_chaninfo __user *arg)
503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
50434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
505a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	struct comedi_chaninfo it;
506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
507a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.subdev >= dev->n_subdevices)
511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + it.subdev;
513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.maxdata_list) {
515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->maxdata || !s->maxdata_list)
516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.maxdata_list, s->maxdata_list,
518790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton				 s->n_chan * sizeof(unsigned int)))
519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.flaglist) {
523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->flaglist)
524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_to_user(it.flaglist, s->flaglist,
526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 s->n_chan * sizeof(unsigned int)))
527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EFAULT;
528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (it.rangelist) {
531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int i;
532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!s->range_table_list)
534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -EINVAL;
535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < s->n_chan; i++) {
536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			int x;
537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
539476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    (s->range_table_list[i]->length);
540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			put_user(x, it.rangelist + i);
541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
542476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0
543476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (copy_to_user(it.rangelist, s->range_type_list,
5440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 s->n_chan * sizeof(unsigned int)))
545476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			return -EFAULT;
546476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif
547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*
553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    COMEDI_BUFINFO
554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    buffer information ioctl
555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    arg:
557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    pointer to bufinfo structure
558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    reads:
560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    bufinfo at arg
561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    writes:
563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef    modified bufinfo at arg
564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef  */
56692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufinfo_ioctl(struct comedi_device *dev,
56753fa827e295d8b09a2446b3126577244644d256dIan Abbott			    struct comedi_bufinfo __user *arg, void *file)
568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
5699aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	struct comedi_bufinfo bi;
57034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
571d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
5739aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + bi.subdevice;
58053fa827e295d8b09a2446b3126577244644d256dIan Abbott
58153fa827e295d8b09a2446b3126577244644d256dIan Abbott	if (s->lock && s->lock != file)
58253fa827e295d8b09a2446b3126577244644d256dIan Abbott		return -EACCES;
58353fa827e295d8b09a2446b3126577244644d256dIan Abbott
584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async) {
587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice does not have async capability\n");
588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_ptr = 0;
589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_ptr = 0;
590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_write_count = 0;
591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.buf_read_count = 0;
5924772c018e35b6a21e8a8bde54568b59998540a16Ian Abbott		bi.bytes_read = 0;
5934772c018e35b6a21e8a8bde54568b59998540a16Ian Abbott		bi.bytes_written = 0;
594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto copyback;
595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
59653fa827e295d8b09a2446b3126577244644d256dIan Abbott	if (!s->busy) {
59753fa827e295d8b09a2446b3126577244644d256dIan Abbott		bi.bytes_read = 0;
59853fa827e295d8b09a2446b3126577244644d256dIan Abbott		bi.bytes_written = 0;
59953fa827e295d8b09a2446b3126577244644d256dIan Abbott		goto copyback_position;
60053fa827e295d8b09a2446b3126577244644d256dIan Abbott	}
60153fa827e295d8b09a2446b3126577244644d256dIan Abbott	if (s->busy != file)
60253fa827e295d8b09a2446b3126577244644d256dIan Abbott		return -EACCES;
603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, bi.bytes_read);
607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
609476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman							  SRF_RUNNING))
610476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    && async->buf_write_count == async->buf_read_count) {
611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			do_become_nonbusy(dev, s);
612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		bi.bytes_written =
617476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    comedi_buf_write_alloc(async, bi.bytes_written);
618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, bi.bytes_written);
619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
62153fa827e295d8b09a2446b3126577244644d256dIan Abbottcopyback_position:
622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_count = async->buf_write_count;
623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_write_ptr = async->buf_write_ptr;
624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_count = async->buf_read_count;
625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	bi.buf_read_ptr = async->buf_read_ptr;
626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
627476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback:
6289aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
6350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file);
636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
63720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSNLIST
63820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
64020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
64120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to sync cmd structure
642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
64320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
64420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		sync cmd struct at arg
64520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		instruction list
64620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
64820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
64920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */
652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256
65392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev,
65492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			     struct comedi_insnlist __user *arg, void *file)
655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
656da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	struct comedi_insnlist insnlist;
65790035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn *insns = NULL;
658790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i = 0;
660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
662da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
665790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
6720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	insns =
6730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!insns) {
675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("kmalloc failed\n");
676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(insns, insnlist.insns,
68190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("copy_from_user failed\n");
683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < insnlist.n_insns; i++) {
688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].n > MAX_SAMPLES) {
689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("number of samples too large\n");
690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_WRITE) {
694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_from_user(data, insns[i].data,
695790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					   insns[i].n * sizeof(unsigned int))) {
696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_from_user failed\n");
697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = parse_insn(dev, insns + i, data, file);
702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (ret < 0)
703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insns[i].insn & INSN_MASK_READ) {
705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (copy_to_user(insns[i].data, data,
706790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton					 insns[i].n * sizeof(unsigned int))) {
707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("copy_to_user failed\n");
708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EFAULT;
709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				goto error;
710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (need_resched())
713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
716476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
717476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(insns);
718476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn,
7260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    unsigned int *data)
727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
728476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (insn->n < 1)
729476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -EINVAL;
730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	switch (data[0]) {
732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_OUTPUT:
733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_INPUT:
734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DISARM:
735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_RESET:
736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 1)
737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ARM:
740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_DIO_QUERY:
741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BLOCK_SIZE:
742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_FILTER:
743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SERIAL_CLOCK:
744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_BIDIRECTIONAL_DATA:
745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ALT_SOURCE:
746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_COUNTER_MODE:
747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_8254_READ_STATUS:
748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_ROUTING:
749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_ROUTING:
750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_PWM_STATUS:
751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_PERIOD:
752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_PERIOD:
753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 2)
754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_GATE_SRC:
757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_GATE_SRC:
758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_CLOCK_SRC:
759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_CLOCK_SRC:
760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_SET_OTHER_SRC:
761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_COUNTER_STATUS:
762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_SET_H_BRIDGE:
763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_GET_H_BRIDGE:
764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 3)
766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_PWM_OUTPUT:
769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	case INSN_CONFIG_ANALOG_TRIG:
770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->n == 5)
771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 0;
772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
7730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* by default we allow the insn since we don't have checks for
7740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 * all possible cases yet */
775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	default:
7763fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_WARNING
7773fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		       "comedi: no check for data length of config insn id "
7780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "%i is implemented.\n"
7790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Add a check to %s in %s.\n"
7800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       " Assuming n=%i is correct.\n", data[0], __func__,
7810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       __FILE__, insn->n);
782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;
784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
7880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
7890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		      unsigned int *data, void *file)
790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
79134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn->insn & INSN_MASK_SPECIAL) {
796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a non-subdevice instruction */
797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_GTOD:
800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			{
801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				struct timeval tv;
802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (insn->n != 2) {
804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_gettimeofday(&tv);
809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[0] = tv.tv_sec;
810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				data[1] = tv.tv_usec;
811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 2;
812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WAIT:
816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1 || data[0] >= 100000) {
817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			udelay(data[0] / 1000);
821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = 1;
822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_INTTRIG:
824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 1) {
825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->subdev >= dev->n_subdevices) {
829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("%d not usable subdevice\n",
830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					insn->subdev);
831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + insn->subdev;
835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async) {
836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no async\n");
837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->async->inttrig) {
841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				DPRINTK("no inttrig\n");
842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EAGAIN;
843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->async->inttrig(dev, s, insn->data[0]);
846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret >= 0)
847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = 1;
848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("invalid insn\n");
851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* a subdevice instruction */
856790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		unsigned int maxdata;
857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (insn->subdev >= dev->n_subdevices) {
859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("subdevice %d out of range\n", insn->subdev);
860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + insn->subdev;
864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->type == COMEDI_SUBD_UNUSED) {
866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("%d not usable subdevice\n", insn->subdev);
867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EIO;
868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* are we locked? (ioctl lock) */
872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->lock && s->lock != file) {
873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("device locked\n");
874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EACCES;
875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
8780fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, 1, &insn->chanspec);
879476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanspec\n");
882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy) {
886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EBUSY;
887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto out;
888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* This looks arbitrary.  It is. */
890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = &parse_insn;
891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		switch (insn->insn) {
892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_READ:
893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_read(dev, s, insn, data);
894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_WRITE:
896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			maxdata = s->maxdata_list
897476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
898476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			    : s->maxdata;
899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			for (i = 0; i < insn->n; ++i) {
900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (data[i] > maxdata) {
901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					ret = -EINVAL;
902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					DPRINTK("bad data value(s)\n");
903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					break;
904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret == 0)
907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = s->insn_write(dev, s, insn, data);
908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_BITS:
910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (insn->n != 2) {
911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				ret = -EINVAL;
912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_bits(dev, s, insn, data);
915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		case INSN_CONFIG:
917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = check_insn_config_length(insn, data);
918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (ret)
919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = s->insn_config(dev, s, insn, data);
921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		default:
923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EINVAL;
924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->busy = NULL;
928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
930476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout:
931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
93520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	COMEDI_INSN
93620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	synchronous instructions
937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
93820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	arg:
93920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		pointer to insn
940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
94120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	reads:
94220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		struct comedi_insn struct at arg
94320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for writes)
944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef *
94520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *	writes:
94620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere *		data (for reads)
947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
94892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev,
94992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			 struct comedi_insn __user *arg, void *file)
950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
95190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn insn;
952790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int *data = NULL;
953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
955790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!data) {
957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
96190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is where the behavior of insn and insnlist deviate. */
967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.n > MAX_SAMPLES)
968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		insn.n = MAX_SAMPLES;
969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_WRITE) {
97021fe2eea6381845956322e63e441f351774de7f9Mark		if (copy_from_user(data,
97121fe2eea6381845956322e63e441f351774de7f9Mark				   insn.data,
97221fe2eea6381845956322e63e441f351774de7f9Mark				   insn.n * sizeof(unsigned int))) {
973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = parse_insn(dev, &insn, data, file);
978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto error;
980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (insn.insn & INSN_MASK_READ) {
98121fe2eea6381845956322e63e441f351774de7f9Mark		if (copy_to_user(insn.data,
98221fe2eea6381845956322e63e441f351774de7f9Mark				 data,
98321fe2eea6381845956322e63e441f351774de7f9Mark				 insn.n * sizeof(unsigned int))) {
984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto error;
986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = insn.n;
989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
990476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror:
991476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(data);
992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
996181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartmanstatic void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
997181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman					  unsigned mask, unsigned bits)
998181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman{
999181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	unsigned long flags;
1000181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman
1001181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1002181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	s->runflags &= ~mask;
1003181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	s->runflags |= (bits & mask);
1004181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1005181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman}
1006181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman
100792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev,
100892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			struct comedi_cmd __user *cmd, void *file)
1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1010ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
101134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1012d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
101492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	unsigned int __user *chanlist_saver = NULL;
1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
101692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1020476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we locked? (ioctl lock) */
1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file) {
1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice locked\n");
1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* are we busy? */
1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy) {
1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice busy\n");
1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = file;
1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %u > %d\n",
1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too short */
1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len < 1) {
1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too short %u < 1\n",
1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len);
1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1071476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(async->cmd.chanlist);
1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd = user_cmd;
1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.data = NULL;
1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cmd.chanlist =
1076476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->cmd.chanlist) {
1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("allocation failed\n");
1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1084476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			   async->cmd.chanlist_len * sizeof(int))) {
1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("fault reading chanlist\n");
1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure each element in channel/gain list is valid */
109121fe2eea6381845956322e63e441f351774de7f9Mark	ret = comedi_check_chanlist(s,
109221fe2eea6381845956322e63e441f351774de7f9Mark				    async->cmd.chanlist_len,
109321fe2eea6381845956322e63e441f351774de7f9Mark				    async->cmd.chanlist);
1094476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (ret < 0) {
1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad chanlist\n");
1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &async->cmd);
1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cmd.flags & TRIG_BOGUS || ret) {
1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("test returned %d\n", ret);
1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd = async->cmd;
1104476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* restore chanlist pointer before copying back */
1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist_saver;
1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.data = NULL;
110792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman		if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault writing cmd\n");
1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EAGAIN;
1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!async->prealloc_bufsz) {
1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -ENOMEM;
1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no buffer (?)\n");
1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_reset_async_buf(async);
1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->cb_mask =
1125476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1126476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    COMEDI_CB_OVERFLOW;
1127476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (async->cmd.flags & TRIG_WAKE_EOS)
1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->cb_mask |= COMEDI_CB_EOS;
1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmd(dev, s);
1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret == 0)
1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1136476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CMDTEST
1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	command testing ioctl
1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		pointer to cmd structure
1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cmd structure at arg
1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		channel/range list
1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		modified cmd structure at arg
1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
115792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev,
115892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    struct comedi_cmd __user *arg, void *file)
1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1160ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd user_cmd;
116134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int *chanlist = NULL;
116492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman	unsigned int __user *chanlist_saver = NULL;
1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1166ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EFAULT;
1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1170476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* save user's chanlist pointer so it can be restored later */
1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	chanlist_saver = user_cmd.chanlist;
1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.subdev >= dev->n_subdevices) {
1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + user_cmd.subdev;
1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->type == COMEDI_SUBD_UNUSED) {
1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->do_cmd || !s->do_cmdtest) {
1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("subdevice %i does not support commands\n",
1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.subdev);
1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* make sure channel/gain list isn't too long */
1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist_len > s->len_chanlist) {
1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("channel/gain list too long %d > %d\n",
1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			user_cmd.chanlist_len, s->len_chanlist);
1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EINVAL;
1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* load channel/gain list */
1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (user_cmd.chanlist) {
1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		chanlist =
1201476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!chanlist) {
1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("allocation failed\n");
1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -ENOMEM;
1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (copy_from_user(chanlist, user_cmd.chanlist,
1209476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   user_cmd.chanlist_len * sizeof(int))) {
1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("fault reading chanlist\n");
1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			ret = -EFAULT;
1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/* make sure each element in channel/gain list is valid */
12160fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
1217476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (ret < 0) {
1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			DPRINTK("bad chanlist\n");
1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto cleanup;
1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		user_cmd.chanlist = chanlist;
1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	ret = s->do_cmdtest(dev, s, &user_cmd);
1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1227476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* restore chanlist pointer before copying back */
1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	user_cmd.chanlist = chanlist_saver;
1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1230ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("bad cmd address\n");
1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EFAULT;
1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto cleanup;
1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1235476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup:
1236476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	kfree(chanlist);
1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_LOCK
1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	lock subdevice
1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
12570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
126134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
12675f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
1268476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->busy || s->lock)
1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = -EBUSY;
1270476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = file;
12725f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (ret < 0)
1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return ret;
1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock_f)
1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->lock_f(dev, s);
1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_UNLOCK
1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unlock subdevice
1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		none
1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	This function isn't protected by the semaphore, since
1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	we already own the lock.
1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
13020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
130434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy)
1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock == file) {
1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0
1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->unlock)
1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s->unlock(dev, s);
1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->lock = NULL;
1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_CANCEL
1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cancel acquisition ioctl
1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
13430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			   void *file)
1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
134534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async == NULL)
1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return do_cancel(dev, s);
1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	COMEDI_POLL ioctl
1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	instructs driver to synchronize buffers
1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	arg:
1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		subdevice number
1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	reads:
1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	writes:
1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nothing
1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/
13790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
13800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 void *file)
1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
138234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (arg >= dev->n_subdevices)
1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EINVAL;
1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = dev->subdevices + arg;
1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->lock && s->lock != file)
1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EACCES;
1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy)
1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file)
1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->poll)
1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return s->poll(dev, s);
1399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return -EINVAL;
1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
140334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int ret = 0;
1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		ret = s->cancel(dev, s);
1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	do_become_nonbusy(dev, s);
1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return ret;
1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
141592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_unmap(struct vm_area_struct *area)
1416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1417d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
141871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev;
1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = area->vm_private_data;
1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev = async->subdevice->device;
1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count--;
1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = {
14290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.close = comedi_unmap,
1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1435476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1436476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
143771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1438d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = NULL;
1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long start = vma->vm_start;
1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long size;
1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n_pages;
1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
144434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1452476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (vma->vm_flags & VM_WRITE)
1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_write_subdevice(dev_file_info);
1454476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	else
1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = comedi_get_read_subdevice(dev_file_info);
1456476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async == NULL) {
1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (vma->vm_pgoff != 0) {
1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("comedi: mmap() offset must be 0.\n");
1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EINVAL;
1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	size = vma->vm_end - vma->vm_start;
1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size > async->prealloc_bufsz) {
1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (size & (~PAGE_MASK)) {
1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EFAULT;
1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	n_pages = size >> PAGE_SHIFT;
1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < n_pages; ++i) {
1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (remap_pfn_range(vma, start,
14860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    page_to_pfn(virt_to_page
14870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						(async->buf_page_list
14880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						 [i].virt_addr)), PAGE_SIZE,
14890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    PAGE_SHARED)) {
1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EAGAIN;
1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			goto done;
1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		start += PAGE_SIZE;
1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_ops = &comedi_vm_ops;
1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	vma->vm_private_data = async;
1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async->mmap_count++;
1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = 0;
1502476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone:
1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return retval;
1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
15070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait)
1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned int mask = 0;
1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1511476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1512476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
151371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
151434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *read_subdev;
151534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *write_subdev;
1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mask = 0;
1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	read_subdev = comedi_get_read_subdevice(dev_file_info);
1526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (read_subdev) {
1527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &read_subdev->async->wait_head, wait);
1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!read_subdev->busy
1529476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_read_n_available(read_subdev->async) > 0
1530476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(read_subdev) &
1531476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)) {
1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLIN | POLLRDNORM;
1533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	write_subdev = comedi_get_write_subdevice(dev_file_info);
1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (write_subdev) {
1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		poll_wait(file, &write_subdev->async->wait_head, wait);
1538476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		comedi_buf_write_alloc(write_subdev->async,
1539476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				       write_subdev->async->prealloc_bufsz);
1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!write_subdev->busy
1541476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || !(comedi_get_subdevice_runflags(write_subdev) &
1542476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			 SRF_RUNNING)
1543476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1544476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		    bytes_per_sample(write_subdev->async->subdevice)) {
1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mask |= POLLOUT | POLLWRNORM;
1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return mask;
1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
155392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_write(struct file *file, const char __user *buf,
155492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman			    size_t nbytes, loff_t *offset)
1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
155634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1557d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1561476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1562476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
156371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_write_subdevice(dev_file_info);
1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1594d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott		if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1595d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			if (count == 0) {
1596d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				if (comedi_get_subdevice_runflags(s) &
1597d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					SRF_ERROR) {
1598d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					retval = -EPIPE;
1599d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				} else {
1600d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott					retval = 0;
1601d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				}
1602d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott				do_become_nonbusy(dev, s);
1603d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			}
1604d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott			break;
1605d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott		}
1606d261154057c27f6c1d256b6198b0ad08733f1758Ian Abbott
1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = n;
1610476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_write_ptr;
1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1613476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (m > comedi_buf_write_n_allocated(async))
1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = comedi_buf_write_n_allocated(async);
1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1628476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (!s->busy)
1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1638476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				   buf, n);
1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_write_free(async, n);
1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1655476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
165892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
16596705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini				loff_t *offset)
1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
166134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
1662d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async;
1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int n, m, count = 0, retval = 0;
1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	DECLARE_WAITQUEUE(wait, current);
1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1666476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1667476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
166871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached) {
1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -ENODEV;
1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s = comedi_get_read_subdevice(dev_file_info);
1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s == NULL) {
1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EIO;
1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	async = s->async;
1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!nbytes) {
1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!s->busy) {
1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = 0;
1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->busy != file) {
1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		retval = -EACCES;
1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto done;
1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	add_wait_queue(&async->wait_head, &wait);
1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	while (nbytes > 0 && !retval) {
1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		set_current_state(TASK_INTERRUPTIBLE);
1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		n = nbytes;
1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = comedi_buf_read_n_available(async);
1702476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d available\n",m); */
1703476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			m = async->prealloc_bufsz - async->buf_read_ptr;
1705476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		/* printk("%d contiguous\n",m); */
1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m < n)
1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n = m;
1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (n == 0) {
1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_become_nonbusy(dev, s);
1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				if (comedi_get_subdevice_runflags(s) &
1713476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				    SRF_ERROR) {
1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = -EPIPE;
1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				} else {
1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef					retval = 0;
1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				}
1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (file->f_flags & O_NONBLOCK) {
1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EAGAIN;
1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (signal_pending(current)) {
1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -ERESTARTSYS;
1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			schedule();
1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (!s->busy) {
1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = 0;
1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (s->busy != file) {
1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				retval = -EACCES;
1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				break;
1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			continue;
1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		m = copy_to_user(buf, async->prealloc_buf +
1740476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				 async->buf_read_ptr, n);
1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (m) {
1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			n -= m;
1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			retval = -EFAULT;
1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_alloc(async, n);
1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_buf_read_free(async, n);
1748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		count += n;
1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		nbytes -= n;
1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		buf += n;
1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		break;		/* makes device work like a pipe */
1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1756476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    async->buf_read_count - async->buf_write_count == 0) {
1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		do_become_nonbusy(dev, s);
1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	set_current_state(TASK_RUNNING);
1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	remove_wait_queue(&async->wait_head, &wait);
1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone:
1763476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	return count ? count : retval;
1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/*
1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef   This function restores a subdevice to an idle state.
1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */
176934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1771d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async) {
1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_reset_async_buf(async);
1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		async->inttrig = NULL;
1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	} else {
1778476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		printk(KERN_ERR
1779476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		       "BUG: (?) do_become_nonbusy called with async=0\n");
1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->busy = NULL;
1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file)
1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1788476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1789476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
17900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev =
17910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    dev_file_info ? dev_file_info->device : NULL;
1792979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott
1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev == NULL) {
1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("invalid minor number\n");
1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* This is slightly hacky, but we want module autoloading
1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * to work for root.
1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, attached -> ok
1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=0 -> autoload
1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: user opens device, unattached, in_request_module=1 -> fail
1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, attached -> ok
1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=1 -> ok
1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *   (typically called from modprobe)
1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * case: root opens device, unattached, in_request_module=0 -> autoload
1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 *
1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * The last could be changed to "-> ok", which would deny root
1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * autoloading.
1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 */
1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached)
1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1814a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		DPRINTK("in request module\n");
1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1819a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		goto ok;
1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 1;
1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD
1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
182656d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif
1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->in_request_module = 0;
1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1832a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1833a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		mutex_unlock(&dev->mutex);
1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENODEV;
1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok:
1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	__module_get(THIS_MODULE);
1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->attached) {
1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (!try_module_get(dev->driver->module)) {
1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			module_put(THIS_MODULE);
1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			mutex_unlock(&dev->mutex);
1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return -ENOSYS;
1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
18483c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott	if (dev->attached && dev->use_count == 0 && dev->open) {
18493c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		int rc = dev->open(dev);
18503c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		if (rc < 0) {
18513c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			module_put(dev->driver->module);
18523c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			module_put(THIS_MODULE);
18533c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			mutex_unlock(&dev->mutex);
18543c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott			return rc;
18553c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		}
18563c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott	}
1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count++;
1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file)
1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(inode);
1868476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1869476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
187071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
187134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = NULL;
1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (dev->subdevices) {
1877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		for (i = 0; i < dev->n_subdevices; i++) {
1878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			s = dev->subdevices + i;
1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1880476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->busy == file)
1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				do_cancel(dev, s);
1882476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (s->lock == file)
1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				s->lock = NULL;
1884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1886476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached && dev->use_count == 1 && dev->close)
1887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		dev->close(dev);
1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	module_put(THIS_MODULE);
1890476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev->attached)
1891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		module_put(dev->driver->module);
1892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->use_count--;
1894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1897476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (file->f_flags & FASYNC)
1898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_fasync(-1, file, 0);
1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on)
1904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	const unsigned minor = iminor(file->f_dentry->d_inode);
1906476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	struct comedi_device_file_info *dev_file_info =
1907476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	    comedi_get_device_file_info(minor);
1908476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
190971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = dev_file_info->device;
1910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return fasync_helper(fd, file, on, &dev->async_queue);
1912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = {
19150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.owner = THIS_MODULE,
19160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.unlocked_ioctl = comedi_unlocked_ioctl,
19170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.compat_ioctl = comedi_compat_ioctl,
19180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.open = comedi_open,
19190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.release = comedi_close,
19200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.read = comedi_read,
19210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.write = comedi_write,
19220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.mmap = comedi_mmap,
19230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.poll = comedi_poll,
19240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.fasync = comedi_fasync,
1925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef};
1926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1927476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class;
1928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev;
1929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void)
1931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
1933476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
19341dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++)
1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_free_board_minor(i);
1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void)
1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int retval;
1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1943476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1944476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       " - http://www.comedi.org\n");
1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1946a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_num_legacy_minors < 0 ||
1947a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1948a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		printk(KERN_ERR "comedi: error: invalid value for module "
1949a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1950a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1951a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		return -EINVAL;
1952a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	}
1953a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1954a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	/*
1955a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi is unusable if both comedi_autoconfig and
1956a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1957a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 * defaults in that case
1958a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	 */
1959a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1960a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess		comedi_num_legacy_minors = 16;
1961a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess
1962476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	memset(comedi_file_info_table, 0,
1963476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1966476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					COMEDI_NUM_MINORS, "comedi");
1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (retval)
1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_init(&comedi_cdev, &comedi_fops);
1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cdev.owner = THIS_MODULE;
1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kobject_set_name(&comedi_cdev.kobj, "comedi");
1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1974476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EIO;
1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_class = class_create(THIS_MODULE, "comedi");
1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (IS_ERR(comedi_class)) {
19793fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor		printk(KERN_ERR "comedi: failed to create class");
1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		cdev_del(&comedi_cdev);
1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1982476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					 COMEDI_NUM_MINORS);
1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return PTR_ERR(comedi_class);
1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
1985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* XXX requires /proc interface */
1987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_init();
1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
1989476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* create devices files for legacy/manual use */
19901dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr	for (i = 0; i < comedi_num_legacy_minors; i++) {
1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		int minor;
1992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		minor = comedi_alloc_board_minor(NULL);
1993476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (minor < 0) {
1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_cleanup_legacy_minors();
1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			cdev_del(&comedi_cdev);
1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1997476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman						 COMEDI_NUM_MINORS);
1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return minor;
1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void)
2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_cleanup_legacy_minors();
2010476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
2011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		BUG_ON(comedi_file_info_table[i]);
2012476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman
2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	class_destroy(comedi_class);
2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	cdev_del(&comedi_cdev);
2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_proc_cleanup();
2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init);
2021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup);
2022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
202371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s)
2024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
20253fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
20263fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor	       dev->driver->driver_name, s);
2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
202818736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_error);
2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
203034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2032d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton	struct comedi_async *async = s->async;
2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags = 0;
2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags_mask = 0;
2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2036476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	/* DPRINTK("comedi_event 0x%x\n",mask); */
2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return;
2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (s->
20420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
20430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     COMEDI_CB_OVERFLOW)) {
2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_RUNNING;
2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	/* remember if an error event has occured, so an error
2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	 * can be returned the next time the user does a read() */
2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags_mask |= SRF_ERROR;
2050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		runflags |= SRF_ERROR;
2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (runflags_mask) {
2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (async->cb_mask & s->async->events) {
2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2059fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman			wake_up_interruptible(&async->wait_head);
20606705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_READ)
20610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
20626705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini			if (s->subdev_flags & SDF_CMD_WRITE)
20630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		} else {
2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			if (async->cb_func)
2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef				async->cb_func(s->async->events, async->cb_arg);
2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->async->events = 0;
2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
207118736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_event);
2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
207334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned runflags;
2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
20785f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&s->spin_lock, flags);
2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	runflags = s->runflags;
20805f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&s->spin_lock, flags);
2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return runflags;
2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
208318736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_get_subdevice_runflags);
2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
208571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev)
2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
208734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	int i;
2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	if (!dev->attached)
2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return 0;
2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	for (i = 0; i < dev->n_subdevices; i++) {
2094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s = dev->subdevices + i;
2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->busy)
2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		if (s->async && s->async->mmap_count)
2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			return 1;
2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return 0;
2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
210492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_init(struct comedi_device *dev)
2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
210671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	memset(dev, 0, sizeof(struct comedi_device));
2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	spin_lock_init(&dev->spinlock);
2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_init(&dev->mutex);
2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	dev->minor = -1;
2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
211292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_cleanup(struct comedi_device *dev)
2113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2114476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (dev == NULL)
2115476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_lock(&dev->mutex);
2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_detach(dev);
2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_unlock(&dev->mutex);
2119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	mutex_destroy(&dev->mutex);
2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device)
2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
21260bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2128883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2131476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2132476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
213371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2134476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info->device == NULL) {
2135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -ENOMEM;
2137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_device_init(info->device);
21395f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2140476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2141476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
21465f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2147476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_BOARD_MINORS) {
2148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		comedi_device_cleanup(info->device);
2149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info->device);
2150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
21510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
215221fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: error: "
215321fe2eea6381845956322e63e441f351774de7f9Mark		       "ran out of minor numbers for board device files.\n");
2154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device->minor = i;
2157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2158476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL,
2159476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     hardware_device, "comedi%i", i);
2160476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		info->device->class_dev = csdev;
2162883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2163883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2164883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
216621fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
216721fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2169883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2170883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2171883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2172883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2173883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
217521fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
217621fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2178883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2179883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2180883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2181883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2182883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
218421fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
218521fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2187883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2188883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2189883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2190883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2191883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
21920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
219321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
219421fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
21950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2196883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_board_minor(i);
2197883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2198883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor)
2203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
22085f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
2210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[minor] = NULL;
22115f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2213476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info) {
221471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton		struct comedi_device *dev = info->device;
2215476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (dev) {
2216476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman			if (dev->class_dev) {
2217476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				device_destroy(comedi_class,
2218476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman					       MKDEV(COMEDI_MAJOR, dev->minor));
2219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			}
2220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_device_cleanup(dev);
2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			kfree(dev);
2222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
2224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2227883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev,
2228883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				 struct comedi_subdevice *s)
2229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
22320bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton	struct device *csdev;
2233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned i;
2234883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2237476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (info == NULL)
2238476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return -ENOMEM;
2239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->device = dev;
2240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->read_subdevice = s;
2241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info->write_subdevice = s;
22425f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
22434c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2244476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		if (comedi_file_info_table[i] == NULL) {
2245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			comedi_file_info_table[i] = info;
2246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef			break;
2247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		}
2248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
22495f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2250476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (i == COMEDI_NUM_MINORS) {
2251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		kfree(info);
22520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
225321fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: error: "
225421fe2eea6381845956322e63e441f351774de7f9Mark		       "ran out of minor numbers for board device files.\n");
2255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		return -EBUSY;
2256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	s->minor = i;
2258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2259476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2260476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     "comedi%i_subd%i", dev->minor,
2261476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman				     (int)(s - dev->subdevices));
2262476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (!IS_ERR(csdev))
2263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = csdev;
2264883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	dev_set_drvdata(csdev, info);
2265883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2266883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
226821fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
226921fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_read_buffer_kb.attr.name);
2271883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2272883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2273883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2274883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2275883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
227721fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
227821fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_read_buffer_kb.attr.name);
2280883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2281883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2282883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2283883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2284883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
228621fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
228721fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_max_write_buffer_kb.attr.name);
2289883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2290883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2291883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2292883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2293883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval) {
22940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk(KERN_ERR
229521fe2eea6381845956322e63e441f351774de7f9Mark		       "comedi: "
229621fe2eea6381845956322e63e441f351774de7f9Mark		       "failed to create sysfs attribute file \"%s\".\n",
22970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev_attr_write_buffer_kb.attr.name);
2298883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		comedi_free_subdevice_minor(s);
2299883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2300883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return i;
2302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
230434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s)
2305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2309476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s == NULL)
2310476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2311476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->minor < 0)
2312476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman		return;
2313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
23175f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[s->minor];
2319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	comedi_file_info_table[s->minor] = NULL;
23205f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2322476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman	if (s->class_dev) {
2323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef		s->class_dev = NULL;
2325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	}
2326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	kfree(info);
2327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
2328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{
2331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	unsigned long flags;
2332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	struct comedi_device_file_info *info;
2333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef
2334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	BUG_ON(minor >= COMEDI_NUM_MINORS);
23355f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	info = comedi_file_info_table[minor];
23375f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef	return info;
2339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}
234018736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_get_device_file_info);
2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev,
2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_subdevice *s,
2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			       struct comedi_async *async, unsigned new_size)
2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2347883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2348883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (new_size > async->max_bufsize)
2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EPERM;
2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->busy) {
2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is busy, cannot resize buffer\n");
2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2354883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2355883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (async->mmap_count) {
2356883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EBUSY;
2358883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (!async->prealloc_buf)
2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2363883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	/* make sure buffer is an integral number of pages
23640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 * (we round up) */
2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = comedi_buf_alloc(dev, s, new_size);
2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2370883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2371883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (s->buf_change) {
2372883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		retval = s->buf_change(dev, s, new_size);
2373883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		if (retval < 0)
2374883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess			return retval;
2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2376883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2377883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2378b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2379883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return 0;
2380883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2381883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2382883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */
2383883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2384883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024;
2385883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev,
2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				       struct device_attribute *attr, char *buf)
2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2389883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2390883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
23930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2395883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2396883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
2397883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2398883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async) {
2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = read_subdevice->async->max_bufsize /
24000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2403883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2404883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2406883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2407883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2408883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev,
2409883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					const char *buf, size_t count)
2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2415883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2417883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2419883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2421883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
24230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2432883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2433883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	read_subdevice->async->max_bufsize = new_max_size;
2434883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2438883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2439883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = {
2440883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
24410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_read_buffer_kb",
24420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2443883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_read_buffer_kb,
2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_read_buffer_kb
2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2446883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2447883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev,
2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				   struct device_attribute *attr, char *buf)
2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice &&
24580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
24590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    read_subdevice->async) {
2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
24610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2462883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
24630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2468883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2469883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev,
2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr,
2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    const char *buf, size_t count)
2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const read_subdevice =
24780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_read_subdevice(info);
2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2481883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2483883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
24840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
24850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2486883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2488883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2489883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (read_subdevice == NULL ||
2490883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2491883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    read_subdevice->async == NULL) {
2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, read_subdevice,
2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     read_subdevice->async, new_size);
2497883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2503883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2504883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = {
2505883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "read_buffer_kb",
25070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_read_buffer_kb,
2509883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_read_buffer_kb
2510883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2511883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev,
2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					struct device_attribute *attr,
2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					char *buf)
2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned max_buffer_size_kb = 0;
2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2523883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		max_buffer_size_kb = write_subdevice->async->max_bufsize /
25270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2530883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev,
2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 struct device_attribute *attr,
2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess					 const char *buf, size_t count)
2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_max_size_kb;
2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_max_size;
2542883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2544883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_max_size_kb))
2546883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2548883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
25490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
25500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_max_size != (uint32_t) new_max_size)
2551883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2552883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2553883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2559883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	write_subdevice->async->max_bufsize = new_max_size;
2561883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2565883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2566883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = {
2567883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
25680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "max_write_buffer_kb",
25690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR},
2570883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_max_write_buffer_kb,
2571883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_max_write_buffer_kb
2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2573883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev,
2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				    struct device_attribute *attr, char *buf)
2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	ssize_t retval;
2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned buffer_size_kb = 0;
2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
25810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice &&
2585883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async) {
2587883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
25880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    bytes_per_kibi;
2589883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
25900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2591883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2592883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2593883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return retval;
2594883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2595883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2596883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev,
2597883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     struct device_attribute *attr,
2598883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess				     const char *buf, size_t count)
2599883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{
2600883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2601883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	unsigned long new_size_kb;
2602883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	uint64_t new_size;
2603883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	int retval;
2604883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	struct comedi_subdevice *const write_subdevice =
26050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    comedi_get_write_subdevice(info);
2606883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2607883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (strict_strtoul(buf, 10, &new_size_kb))
2608883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
26090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size_kb != (uint32_t) new_size_kb)
2610883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
26110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
26120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (new_size != (uint32_t) new_size)
2613883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2614883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2615883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_lock(&info->device->mutex);
2616883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (write_subdevice == NULL ||
2617883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2618883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	    write_subdevice->async == NULL) {
2619883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		mutex_unlock(&info->device->mutex);
2620883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return -EINVAL;
2621883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	}
2622883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	retval = resize_async_buffer(info->device, write_subdevice,
26230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     write_subdevice->async, new_size);
2624883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	mutex_unlock(&info->device->mutex);
2625883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2626883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	if (retval < 0)
2627883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess		return retval;
2628883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	return count;
2629883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}
2630883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess
2631883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = {
2632883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.attr = {
26330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .name = "write_buffer_kb",
26340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2635883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.show = &show_write_buffer_kb,
2636883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess	.store = &store_write_buffer_kb
2637883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess};
2638