blob: f3d59e2a1152b5626caa9c7e7e0ebd9f50f587b6 [file] [log] [blame]
David Schleefed9eccb2008-11-04 20:29:31 -08001/*
2 comedi/comedi_fops.c
3 comedi kernel module
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
David Schleefed9eccb2008-11-04 20:29:31 -080017*/
18
19#undef DEBUG
20
David Schleefed9eccb2008-11-04 20:29:31 -080021#include "comedi_compat32.h"
22
23#include <linux/module.h>
24#include <linux/errno.h>
25#include <linux/kernel.h>
26#include <linux/sched.h>
27#include <linux/fcntl.h>
28#include <linux/delay.h>
David Schleefed9eccb2008-11-04 20:29:31 -080029#include <linux/mm.h>
30#include <linux/slab.h>
31#include <linux/kmod.h>
32#include <linux/poll.h>
33#include <linux/init.h>
34#include <linux/device.h>
35#include <linux/vmalloc.h>
36#include <linux/fs.h>
37#include "comedidev.h"
38#include <linux/cdev.h>
Frank Mori Hess883db3d2009-04-14 11:21:41 -040039#include <linux/stat.h>
David Schleefed9eccb2008-11-04 20:29:31 -080040
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -080041#include <linux/io.h>
42#include <linux/uaccess.h>
David Schleefed9eccb2008-11-04 20:29:31 -080043
Ian Abbott3a5fa272012-06-19 10:17:44 +010044#include "comedi_internal.h"
David Schleefed9eccb2008-11-04 20:29:31 -080045
Ian Abbotteda56822013-04-04 14:59:02 +010046#define COMEDI_NUM_MINORS 0x100
Ian Abbott5b7dba12013-04-04 14:59:04 +010047#define COMEDI_NUM_SUBDEVICE_MINORS \
48 (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
Ian Abbotteda56822013-04-04 14:59:02 +010049
David Schleefed9eccb2008-11-04 20:29:31 -080050#ifdef CONFIG_COMEDI_DEBUG
51int comedi_debug;
H Hartley Sweeten5660e742013-04-12 10:11:54 -070052EXPORT_SYMBOL_GPL(comedi_debug);
Ian Abbott4d7df822012-04-13 14:12:53 +010053module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
54MODULE_PARM_DESC(comedi_debug,
55 "enable comedi core and driver debugging if non-zero (default 0)"
56 );
David Schleefed9eccb2008-11-04 20:29:31 -080057#endif
58
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -070059static int comedi_num_legacy_minors;
Ian Abbott4d7df822012-04-13 14:12:53 +010060module_param(comedi_num_legacy_minors, int, S_IRUGO);
61MODULE_PARM_DESC(comedi_num_legacy_minors,
62 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
63 );
64
Ian Abbott234bb3c2012-04-13 14:12:54 +010065unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
Ian Abbott4d7df822012-04-13 14:12:53 +010066module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
67MODULE_PARM_DESC(comedi_default_buf_size_kb,
68 "default asynchronous buffer size in KiB (default "
Ian Abbott234bb3c2012-04-13 14:12:54 +010069 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
Ian Abbott4d7df822012-04-13 14:12:53 +010070
Ian Abbott234bb3c2012-04-13 14:12:54 +010071unsigned int comedi_default_buf_maxsize_kb
72 = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
Ian Abbott4d7df822012-04-13 14:12:53 +010073module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
74MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
75 "default maximum size of asynchronous buffer in KiB (default "
Ian Abbott234bb3c2012-04-13 14:12:54 +010076 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
Bernd Porr1dd33ab2008-12-08 23:30:13 +000077
Ian Abbott5b7dba12013-04-04 14:59:04 +010078static DEFINE_MUTEX(comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +010079static struct comedi_device
Ian Abbott5b7dba12013-04-04 14:59:04 +010080*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
81
82static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
83/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
Ian Abbottbd5b4172013-04-04 14:59:15 +010084static struct comedi_subdevice
Ian Abbott5b7dba12013-04-04 14:59:04 +010085*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
David Schleefed9eccb2008-11-04 20:29:31 -080086
Ian Abbottd9740a02013-04-04 14:58:55 +010087static struct class *comedi_class;
88static struct cdev comedi_cdev;
89
90static void comedi_device_init(struct comedi_device *dev)
91{
92 spin_lock_init(&dev->spinlock);
93 mutex_init(&dev->mutex);
94 dev->minor = -1;
95}
96
97static void comedi_device_cleanup(struct comedi_device *dev)
98{
99 struct module *driver_module = NULL;
100
101 if (dev == NULL)
102 return;
103 mutex_lock(&dev->mutex);
104 if (dev->attached)
105 driver_module = dev->driver->module;
106 comedi_device_detach(dev);
107 while (dev->use_count > 0) {
108 if (driver_module)
109 module_put(driver_module);
110 module_put(THIS_MODULE);
111 dev->use_count--;
112 }
113 mutex_unlock(&dev->mutex);
114 mutex_destroy(&dev->mutex);
115}
116
Ian Abbottdb210da2013-04-04 14:59:18 +0100117static bool comedi_clear_board_dev(struct comedi_device *dev)
118{
119 unsigned int i = dev->minor;
120 bool cleared = false;
121
122 mutex_lock(&comedi_board_minor_table_lock);
123 if (dev == comedi_board_minor_table[i]) {
124 comedi_board_minor_table[i] = NULL;
125 cleared = true;
126 }
127 mutex_unlock(&comedi_board_minor_table_lock);
128 return cleared;
129}
130
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100131static struct comedi_device *comedi_clear_board_minor(unsigned minor)
Ian Abbottd9740a02013-04-04 14:58:55 +0100132{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100133 struct comedi_device *dev;
Ian Abbottd9740a02013-04-04 14:58:55 +0100134
Ian Abbott5b7dba12013-04-04 14:59:04 +0100135 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100136 dev = comedi_board_minor_table[minor];
Ian Abbott5b7dba12013-04-04 14:59:04 +0100137 comedi_board_minor_table[minor] = NULL;
138 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100139 return dev;
Ian Abbottd9740a02013-04-04 14:58:55 +0100140}
141
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100142static void comedi_free_board_dev(struct comedi_device *dev)
Ian Abbottd9740a02013-04-04 14:58:55 +0100143{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100144 if (dev) {
145 if (dev->class_dev) {
146 device_destroy(comedi_class,
147 MKDEV(COMEDI_MAJOR, dev->minor));
Ian Abbottd9740a02013-04-04 14:58:55 +0100148 }
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100149 comedi_device_cleanup(dev);
150 kfree(dev);
Ian Abbottd9740a02013-04-04 14:58:55 +0100151 }
152}
Ian Abbott8ab4ed62013-04-04 14:58:54 +0100153
Ian Abbottbd5b4172013-04-04 14:59:15 +0100154static struct comedi_subdevice
155*comedi_subdevice_from_minor(unsigned minor)
Ian Abbott5b7dba12013-04-04 14:59:04 +0100156{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100157 struct comedi_subdevice *s;
Ian Abbott5b7dba12013-04-04 14:59:04 +0100158 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
159
160 BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
161 mutex_lock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +0100162 s = comedi_subdevice_minor_table[i];
Ian Abbott5b7dba12013-04-04 14:59:04 +0100163 mutex_unlock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +0100164 return s;
Ian Abbott5b7dba12013-04-04 14:59:04 +0100165}
166
Ian Abbottf3abc832013-04-04 14:59:12 +0100167static struct comedi_device *comedi_dev_from_board_minor(unsigned minor)
168{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100169 struct comedi_device *dev;
Ian Abbottf3abc832013-04-04 14:59:12 +0100170
Ian Abbottdac59de2013-04-04 14:59:14 +0100171 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
172 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100173 dev = comedi_board_minor_table[minor];
Ian Abbottdac59de2013-04-04 14:59:14 +0100174 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100175 return dev;
Ian Abbottf3abc832013-04-04 14:59:12 +0100176}
177
178static struct comedi_device *comedi_dev_from_subdevice_minor(unsigned minor)
179{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100180 struct comedi_subdevice *s;
Ian Abbottf3abc832013-04-04 14:59:12 +0100181
Ian Abbottbd5b4172013-04-04 14:59:15 +0100182 s = comedi_subdevice_from_minor(minor);
183 return s ? s->device : NULL;
Ian Abbottf3abc832013-04-04 14:59:12 +0100184}
185
H Hartley Sweeten85104e92012-12-19 15:34:40 -0700186struct comedi_device *comedi_dev_from_minor(unsigned minor)
187{
Ian Abbottf3abc832013-04-04 14:59:12 +0100188 if (minor < COMEDI_NUM_BOARD_MINORS)
189 return comedi_dev_from_board_minor(minor);
190 else
191 return comedi_dev_from_subdevice_minor(minor);
H Hartley Sweeten85104e92012-12-19 15:34:40 -0700192}
193EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
194
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700195static struct comedi_subdevice *
Ian Abbottda56fdc2013-04-04 14:59:10 +0100196comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700197{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100198 struct comedi_subdevice *s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100199
200 if (minor >= COMEDI_NUM_BOARD_MINORS) {
Ian Abbottbd5b4172013-04-04 14:59:15 +0100201 s = comedi_subdevice_from_minor(minor);
202 if (!s || s->device != dev)
Ian Abbottda56fdc2013-04-04 14:59:10 +0100203 return NULL;
Ian Abbottbd5b4172013-04-04 14:59:15 +0100204 if (s->subdev_flags & SDF_CMD_READ)
205 return s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100206 }
207 return dev->read_subdev;
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700208}
209
210static struct comedi_subdevice *
Ian Abbottda56fdc2013-04-04 14:59:10 +0100211comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700212{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100213 struct comedi_subdevice *s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100214
215 if (minor >= COMEDI_NUM_BOARD_MINORS) {
Ian Abbottbd5b4172013-04-04 14:59:15 +0100216 s = comedi_subdevice_from_minor(minor);
217 if (!s || s->device != dev)
Ian Abbottda56fdc2013-04-04 14:59:10 +0100218 return NULL;
Ian Abbottbd5b4172013-04-04 14:59:15 +0100219 if (s->subdev_flags & SDF_CMD_WRITE)
220 return s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100221 }
222 return dev->write_subdev;
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700223}
224
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400225static int resize_async_buffer(struct comedi_device *dev,
226 struct comedi_subdevice *s,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700227 struct comedi_async *async, unsigned new_size)
228{
229 int retval;
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400230
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700231 if (new_size > async->max_bufsize)
232 return -EPERM;
233
234 if (s->busy) {
235 DPRINTK("subdevice is busy, cannot resize buffer\n");
236 return -EBUSY;
237 }
238 if (async->mmap_count) {
239 DPRINTK("subdevice is mmapped, cannot resize buffer\n");
240 return -EBUSY;
241 }
242
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700243 /* make sure buffer is an integral number of pages
244 * (we round up) */
245 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
246
247 retval = comedi_buf_alloc(dev, s, new_size);
248 if (retval < 0)
249 return retval;
250
251 if (s->buf_change) {
252 retval = s->buf_change(dev, s, new_size);
253 if (retval < 0)
254 return retval;
255 }
256
257 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700258 dev->minor, s->index, async->prealloc_bufsz);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700259 return 0;
260}
261
262/* sysfs attribute files */
263
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700264static ssize_t max_read_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700265 struct device_attribute *attr, char *buf)
266{
Ian Abbottc88db462013-04-04 14:59:09 +0100267 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100268 struct comedi_device *dev;
269 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700270 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700271
Ian Abbott5e04c252013-04-04 14:59:11 +0100272 dev = comedi_dev_from_minor(minor);
273 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100274 return -ENODEV;
275
Ian Abbott7f4656c2013-04-04 14:59:08 +0100276 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100277 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700278 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
279 size = s->async->max_bufsize / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100280 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700281
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700282 return snprintf(buf, PAGE_SIZE, "%i\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700283}
284
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700285static ssize_t max_read_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700286 struct device_attribute *attr,
287 const char *buf, size_t count)
288{
Ian Abbottc88db462013-04-04 14:59:09 +0100289 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100290 struct comedi_device *dev;
291 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700292 unsigned int size;
293 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700294
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700295 err = kstrtouint(buf, 10, &size);
296 if (err)
297 return err;
298 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700299 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700300 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700301
Ian Abbott5e04c252013-04-04 14:59:11 +0100302 dev = comedi_dev_from_minor(minor);
303 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100304 return -ENODEV;
305
Ian Abbott7f4656c2013-04-04 14:59:08 +0100306 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100307 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700308 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
309 s->async->max_bufsize = size;
310 else
311 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100312 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700313
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700314 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700315}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700316static DEVICE_ATTR_RW(max_read_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700317
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700318static ssize_t read_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700319 struct device_attribute *attr, char *buf)
320{
Ian Abbottc88db462013-04-04 14:59:09 +0100321 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100322 struct comedi_device *dev;
323 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700324 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700325
Ian Abbott5e04c252013-04-04 14:59:11 +0100326 dev = comedi_dev_from_minor(minor);
327 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100328 return -ENODEV;
329
Ian Abbott7f4656c2013-04-04 14:59:08 +0100330 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100331 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700332 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
333 size = s->async->prealloc_bufsz / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100334 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700335
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700336 return snprintf(buf, PAGE_SIZE, "%i\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700337}
338
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700339static ssize_t read_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700340 struct device_attribute *attr,
341 const char *buf, size_t count)
342{
Ian Abbottc88db462013-04-04 14:59:09 +0100343 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100344 struct comedi_device *dev;
345 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700346 unsigned int size;
347 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700348
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700349 err = kstrtouint(buf, 10, &size);
350 if (err)
351 return err;
352 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700353 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700354 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700355
Ian Abbott5e04c252013-04-04 14:59:11 +0100356 dev = comedi_dev_from_minor(minor);
357 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100358 return -ENODEV;
359
Ian Abbott7f4656c2013-04-04 14:59:08 +0100360 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100361 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700362 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
Ian Abbott7f4656c2013-04-04 14:59:08 +0100363 err = resize_async_buffer(dev, s, s->async, size);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700364 else
365 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100366 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700367
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700368 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700369}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700370static DEVICE_ATTR_RW(read_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700371
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700372static ssize_t max_write_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700373 struct device_attribute *attr,
374 char *buf)
375{
Ian Abbottc88db462013-04-04 14:59:09 +0100376 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100377 struct comedi_device *dev;
378 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700379 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700380
Ian Abbott5e04c252013-04-04 14:59:11 +0100381 dev = comedi_dev_from_minor(minor);
382 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100383 return -ENODEV;
384
Ian Abbott7f4656c2013-04-04 14:59:08 +0100385 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100386 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700387 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
388 size = s->async->max_bufsize / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100389 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700390
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700391 return snprintf(buf, PAGE_SIZE, "%i\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700392}
393
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700394static ssize_t max_write_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700395 struct device_attribute *attr,
396 const char *buf, size_t count)
397{
Ian Abbottc88db462013-04-04 14:59:09 +0100398 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100399 struct comedi_device *dev;
400 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700401 unsigned int size;
402 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700403
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700404 err = kstrtouint(buf, 10, &size);
405 if (err)
406 return err;
407 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700408 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700409 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700410
Ian Abbott5e04c252013-04-04 14:59:11 +0100411 dev = comedi_dev_from_minor(minor);
412 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100413 return -ENODEV;
414
Ian Abbott7f4656c2013-04-04 14:59:08 +0100415 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100416 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700417 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
418 s->async->max_bufsize = size;
419 else
420 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100421 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700422
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700423 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700424}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700425static DEVICE_ATTR_RW(max_write_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700426
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700427static ssize_t write_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700428 struct device_attribute *attr, char *buf)
429{
Ian Abbottc88db462013-04-04 14:59:09 +0100430 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100431 struct comedi_device *dev;
432 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700433 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700434
Ian Abbott5e04c252013-04-04 14:59:11 +0100435 dev = comedi_dev_from_minor(minor);
436 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100437 return -ENODEV;
438
Ian Abbott7f4656c2013-04-04 14:59:08 +0100439 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100440 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700441 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
442 size = s->async->prealloc_bufsz / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100443 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700444
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700445 return snprintf(buf, PAGE_SIZE, "%i\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700446}
447
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700448static ssize_t write_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700449 struct device_attribute *attr,
450 const char *buf, size_t count)
451{
Ian Abbottc88db462013-04-04 14:59:09 +0100452 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100453 struct comedi_device *dev;
454 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700455 unsigned int size;
456 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700457
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700458 err = kstrtouint(buf, 10, &size);
459 if (err)
460 return err;
461 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700462 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700463 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700464
Ian Abbott5e04c252013-04-04 14:59:11 +0100465 dev = comedi_dev_from_minor(minor);
466 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100467 return -ENODEV;
468
Ian Abbott7f4656c2013-04-04 14:59:08 +0100469 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100470 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700471 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
Ian Abbott7f4656c2013-04-04 14:59:08 +0100472 err = resize_async_buffer(dev, s, s->async, size);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700473 else
474 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100475 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700476
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700477 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700478}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700479static DEVICE_ATTR_RW(write_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700480
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700481static struct attribute *comedi_dev_attrs[] = {
482 &dev_attr_max_read_buffer_kb.attr,
483 &dev_attr_read_buffer_kb.attr,
484 &dev_attr_max_write_buffer_kb.attr,
485 &dev_attr_write_buffer_kb.attr,
486 NULL,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700487};
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700488ATTRIBUTE_GROUPS(comedi_dev);
David Schleefed9eccb2008-11-04 20:29:31 -0800489
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700490static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
491 unsigned mask, unsigned bits)
492{
493 unsigned long flags;
494
495 spin_lock_irqsave(&s->spin_lock, flags);
496 s->runflags &= ~mask;
497 s->runflags |= (bits & mask);
498 spin_unlock_irqrestore(&s->spin_lock, flags);
499}
500
H Hartley Sweetenade17642012-12-19 15:43:40 -0700501static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
H Hartley Sweeten74120712012-12-19 15:42:26 -0700502{
503 unsigned long flags;
504 unsigned runflags;
505
506 spin_lock_irqsave(&s->spin_lock, flags);
507 runflags = s->runflags;
508 spin_unlock_irqrestore(&s->spin_lock, flags);
509 return runflags;
510}
H Hartley Sweeten74120712012-12-19 15:42:26 -0700511
H Hartley Sweetene0dac312012-12-19 15:42:47 -0700512bool comedi_is_subdevice_running(struct comedi_subdevice *s)
513{
514 unsigned runflags = comedi_get_subdevice_runflags(s);
515
516 return (runflags & SRF_RUNNING) ? true : false;
517}
518EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
519
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -0700520static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
521{
522 unsigned runflags = comedi_get_subdevice_runflags(s);
523
524 return (runflags & SRF_ERROR) ? true : false;
525}
526
H Hartley Sweeten9682e282012-12-19 15:44:24 -0700527static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
528{
529 unsigned runflags = comedi_get_subdevice_runflags(s);
530
531 return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
532}
533
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700534/**
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700535 * comedi_alloc_spriv() - Allocate memory for the subdevice private data.
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700536 * @s: comedi_subdevice struct
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700537 * @size: size of the memory to allocate
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700538 *
539 * This also sets the subdevice runflags to allow the core to automatically
540 * free the private data during the detach.
541 */
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700542void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700543{
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700544 s->private = kzalloc(size, GFP_KERNEL);
545 if (s->private)
Ian Abbott67aa4ac2013-10-07 15:51:58 +0100546 s->runflags |= SRF_FREE_SPRIV;
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700547 return s->private;
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700548}
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700549EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700550
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700551/*
552 This function restores a subdevice to an idle state.
553 */
554static void do_become_nonbusy(struct comedi_device *dev,
555 struct comedi_subdevice *s)
556{
557 struct comedi_async *async = s->async;
558
559 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
560 if (async) {
H Hartley Sweeten61c9fb02013-01-09 13:27:07 -0700561 comedi_buf_reset(async);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700562 async->inttrig = NULL;
563 kfree(async->cmd.chanlist);
564 async->cmd.chanlist = NULL;
565 } else {
566 dev_err(dev->class_dev,
567 "BUG: (?) do_become_nonbusy called with async=NULL\n");
568 }
569
570 s->busy = NULL;
571}
572
573static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
574{
575 int ret = 0;
576
H Hartley Sweetenf0124632012-12-19 15:43:18 -0700577 if (comedi_is_subdevice_running(s) && s->cancel)
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700578 ret = s->cancel(dev, s);
579
580 do_become_nonbusy(dev, s);
581
582 return ret;
583}
584
585static int is_device_busy(struct comedi_device *dev)
586{
587 struct comedi_subdevice *s;
588 int i;
589
590 if (!dev->attached)
591 return 0;
592
593 for (i = 0; i < dev->n_subdevices; i++) {
594 s = &dev->subdevices[i];
595 if (s->busy)
596 return 1;
597 if (s->async && s->async->mmap_count)
598 return 1;
599 }
600
601 return 0;
602}
603
David Schleefed9eccb2008-11-04 20:29:31 -0800604/*
605 COMEDI_DEVCONFIG
606 device config ioctl
607
608 arg:
609 pointer to devconfig structure
610
611 reads:
612 devconfig structure at arg
613
614 writes:
615 none
616*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530617static int do_devconfig_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700618 struct comedi_devconfig __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800619{
Bill Pemberton0707bb02009-03-16 22:06:20 -0400620 struct comedi_devconfig it;
David Schleefed9eccb2008-11-04 20:29:31 -0800621
622 if (!capable(CAP_SYS_ADMIN))
623 return -EPERM;
624
625 if (arg == NULL) {
626 if (is_device_busy(dev))
627 return -EBUSY;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800628 if (dev->attached) {
David Schleefed9eccb2008-11-04 20:29:31 -0800629 struct module *driver_module = dev->driver->module;
630 comedi_device_detach(dev);
631 module_put(driver_module);
632 }
633 return 0;
634 }
635
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700636 if (copy_from_user(&it, arg, sizeof(it)))
David Schleefed9eccb2008-11-04 20:29:31 -0800637 return -EFAULT;
638
639 it.board_name[COMEDI_NAMELEN - 1] = 0;
640
H Hartley Sweetend1843132013-01-09 09:46:10 -0700641 if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
642 dev_warn(dev->class_dev,
643 "comedi_config --init_data is deprecated\n");
644 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -0800645 }
646
Ian Abbott8ab4ed62013-04-04 14:58:54 +0100647 if (dev->minor >= comedi_num_legacy_minors)
648 /* don't re-use dynamically allocated comedi devices */
649 return -EBUSY;
650
Ian Abbottb2a644b2013-04-04 14:58:56 +0100651 /* This increments the driver module count on success. */
652 return comedi_device_attach(dev, &it);
David Schleefed9eccb2008-11-04 20:29:31 -0800653}
654
655/*
656 COMEDI_BUFCONFIG
657 buffer configuration ioctl
658
659 arg:
660 pointer to bufconfig structure
661
662 reads:
663 bufconfig at arg
664
665 writes:
666 modified bufconfig at arg
667
668*/
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700669static int do_bufconfig_ioctl(struct comedi_device *dev,
670 struct comedi_bufconfig __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800671{
Bill Pembertonbe6aba42009-03-16 22:06:37 -0400672 struct comedi_bufconfig bc;
Bill Pembertond1636792009-03-16 22:05:20 -0400673 struct comedi_async *async;
Bill Pemberton34c43922009-03-16 22:05:14 -0400674 struct comedi_subdevice *s;
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400675 int retval = 0;
David Schleefed9eccb2008-11-04 20:29:31 -0800676
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700677 if (copy_from_user(&bc, arg, sizeof(bc)))
David Schleefed9eccb2008-11-04 20:29:31 -0800678 return -EFAULT;
679
Güngör Erseymen11f80dd2013-06-07 21:29:49 +0300680 if (bc.subdevice >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -0800681 return -EINVAL;
682
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700683 s = &dev->subdevices[bc.subdevice];
David Schleefed9eccb2008-11-04 20:29:31 -0800684 async = s->async;
685
686 if (!async) {
687 DPRINTK("subdevice does not have async capability\n");
688 bc.size = 0;
689 bc.maximum_size = 0;
690 goto copyback;
691 }
692
693 if (bc.maximum_size) {
694 if (!capable(CAP_SYS_ADMIN))
695 return -EPERM;
696
697 async->max_bufsize = bc.maximum_size;
698 }
699
700 if (bc.size) {
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400701 retval = resize_async_buffer(dev, s, async, bc.size);
702 if (retval < 0)
703 return retval;
David Schleefed9eccb2008-11-04 20:29:31 -0800704 }
705
706 bc.size = async->prealloc_bufsz;
707 bc.maximum_size = async->max_bufsize;
708
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800709copyback:
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700710 if (copy_to_user(arg, &bc, sizeof(bc)))
David Schleefed9eccb2008-11-04 20:29:31 -0800711 return -EFAULT;
712
713 return 0;
714}
715
716/*
717 COMEDI_DEVINFO
718 device info ioctl
719
720 arg:
721 pointer to devinfo structure
722
723 reads:
724 none
725
726 writes:
727 devinfo structure
728
729*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530730static int do_devinfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700731 struct comedi_devinfo __user *arg,
732 struct file *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800733{
Al Viro6131ffa2013-02-27 16:59:05 -0500734 const unsigned minor = iminor(file_inode(file));
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700735 struct comedi_subdevice *s;
736 struct comedi_devinfo devinfo;
David Schleefed9eccb2008-11-04 20:29:31 -0800737
738 memset(&devinfo, 0, sizeof(devinfo));
739
740 /* fill devinfo structure */
741 devinfo.version_code = COMEDI_VERSION_CODE;
742 devinfo.n_subdevs = dev->n_subdevices;
Vasiliy Kulikov819cbb12011-06-26 12:56:22 +0400743 strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
744 strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
David Schleefed9eccb2008-11-04 20:29:31 -0800745
Ian Abbottda56fdc2013-04-04 14:59:10 +0100746 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700747 if (s)
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700748 devinfo.read_subdevice = s->index;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800749 else
David Schleefed9eccb2008-11-04 20:29:31 -0800750 devinfo.read_subdevice = -1;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800751
Ian Abbottda56fdc2013-04-04 14:59:10 +0100752 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700753 if (s)
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700754 devinfo.write_subdevice = s->index;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800755 else
David Schleefed9eccb2008-11-04 20:29:31 -0800756 devinfo.write_subdevice = -1;
David Schleefed9eccb2008-11-04 20:29:31 -0800757
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700758 if (copy_to_user(arg, &devinfo, sizeof(devinfo)))
David Schleefed9eccb2008-11-04 20:29:31 -0800759 return -EFAULT;
760
761 return 0;
762}
763
764/*
765 COMEDI_SUBDINFO
766 subdevice info ioctl
767
768 arg:
769 pointer to array of subdevice info structures
770
771 reads:
772 none
773
774 writes:
775 array of subdevice info structures at arg
776
777*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530778static int do_subdinfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700779 struct comedi_subdinfo __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800780{
781 int ret, i;
Bill Pembertonbd52efb2009-03-16 22:06:09 -0400782 struct comedi_subdinfo *tmp, *us;
Bill Pemberton34c43922009-03-16 22:05:14 -0400783 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -0800784
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700785 tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL);
David Schleefed9eccb2008-11-04 20:29:31 -0800786 if (!tmp)
787 return -ENOMEM;
788
789 /* fill subdinfo structs */
790 for (i = 0; i < dev->n_subdevices; i++) {
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700791 s = &dev->subdevices[i];
David Schleefed9eccb2008-11-04 20:29:31 -0800792 us = tmp + i;
793
794 us->type = s->type;
795 us->n_chan = s->n_chan;
796 us->subd_flags = s->subdev_flags;
H Hartley Sweetenf0124632012-12-19 15:43:18 -0700797 if (comedi_is_subdevice_running(s))
David Schleefed9eccb2008-11-04 20:29:31 -0800798 us->subd_flags |= SDF_RUNNING;
799#define TIMER_nanosec 5 /* backwards compatibility */
800 us->timer_type = TIMER_nanosec;
801 us->len_chanlist = s->len_chanlist;
802 us->maxdata = s->maxdata;
803 if (s->range_table) {
804 us->range_type =
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800805 (i << 24) | (0 << 16) | (s->range_table->length);
David Schleefed9eccb2008-11-04 20:29:31 -0800806 } else {
807 us->range_type = 0; /* XXX */
808 }
David Schleefed9eccb2008-11-04 20:29:31 -0800809
810 if (s->busy)
811 us->subd_flags |= SDF_BUSY;
812 if (s->busy == file)
813 us->subd_flags |= SDF_BUSY_OWNER;
814 if (s->lock)
815 us->subd_flags |= SDF_LOCKED;
816 if (s->lock == file)
817 us->subd_flags |= SDF_LOCK_OWNER;
818 if (!s->maxdata && s->maxdata_list)
819 us->subd_flags |= SDF_MAXDATA;
David Schleefed9eccb2008-11-04 20:29:31 -0800820 if (s->range_table_list)
821 us->subd_flags |= SDF_RANGETYPE;
822 if (s->do_cmd)
823 us->subd_flags |= SDF_CMD;
824
825 if (s->insn_bits != &insn_inval)
826 us->insn_bits_support = COMEDI_SUPPORTED;
827 else
828 us->insn_bits_support = COMEDI_UNSUPPORTED;
David Schleefed9eccb2008-11-04 20:29:31 -0800829 }
830
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700831 ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp));
David Schleefed9eccb2008-11-04 20:29:31 -0800832
833 kfree(tmp);
834
835 return ret ? -EFAULT : 0;
836}
837
838/*
839 COMEDI_CHANINFO
840 subdevice info ioctl
841
842 arg:
843 pointer to chaninfo structure
844
845 reads:
846 chaninfo structure at arg
847
848 writes:
849 arrays at elements of chaninfo structure
850
851*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530852static int do_chaninfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700853 struct comedi_chaninfo __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800854{
Bill Pemberton34c43922009-03-16 22:05:14 -0400855 struct comedi_subdevice *s;
Bill Pembertona18b4162009-03-16 22:06:04 -0400856 struct comedi_chaninfo it;
David Schleefed9eccb2008-11-04 20:29:31 -0800857
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700858 if (copy_from_user(&it, arg, sizeof(it)))
David Schleefed9eccb2008-11-04 20:29:31 -0800859 return -EFAULT;
860
861 if (it.subdev >= dev->n_subdevices)
862 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700863 s = &dev->subdevices[it.subdev];
David Schleefed9eccb2008-11-04 20:29:31 -0800864
865 if (it.maxdata_list) {
866 if (s->maxdata || !s->maxdata_list)
867 return -EINVAL;
868 if (copy_to_user(it.maxdata_list, s->maxdata_list,
Bill Pemberton790c5542009-03-16 22:05:02 -0400869 s->n_chan * sizeof(unsigned int)))
David Schleefed9eccb2008-11-04 20:29:31 -0800870 return -EFAULT;
871 }
872
Ian Abbott64d9b1d2013-10-07 16:50:05 +0100873 if (it.flaglist)
874 return -EINVAL; /* flaglist not supported */
David Schleefed9eccb2008-11-04 20:29:31 -0800875
876 if (it.rangelist) {
877 int i;
878
879 if (!s->range_table_list)
880 return -EINVAL;
881 for (i = 0; i < s->n_chan; i++) {
882 int x;
883
884 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800885 (s->range_table_list[i]->length);
Vasiliy Kulikov81604d42010-09-05 22:32:33 +0400886 if (put_user(x, it.rangelist + i))
887 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -0800888 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800889#if 0
890 if (copy_to_user(it.rangelist, s->range_type_list,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530891 s->n_chan * sizeof(unsigned int)))
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800892 return -EFAULT;
893#endif
David Schleefed9eccb2008-11-04 20:29:31 -0800894 }
895
896 return 0;
897}
898
899 /*
900 COMEDI_BUFINFO
901 buffer information ioctl
902
903 arg:
904 pointer to bufinfo structure
905
906 reads:
907 bufinfo at arg
908
909 writes:
910 modified bufinfo at arg
911
912 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700913static int do_bufinfo_ioctl(struct comedi_device *dev,
Ian Abbott53fa8272010-05-19 18:09:50 +0100914 struct comedi_bufinfo __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800915{
Bill Pemberton9aa53392009-03-16 22:06:42 -0400916 struct comedi_bufinfo bi;
Bill Pemberton34c43922009-03-16 22:05:14 -0400917 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -0400918 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -0800919
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700920 if (copy_from_user(&bi, arg, sizeof(bi)))
David Schleefed9eccb2008-11-04 20:29:31 -0800921 return -EFAULT;
922
Güngör Erseymen7b1a5e22013-06-07 21:29:50 +0300923 if (bi.subdevice >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -0800924 return -EINVAL;
925
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700926 s = &dev->subdevices[bi.subdevice];
Ian Abbott53fa8272010-05-19 18:09:50 +0100927
928 if (s->lock && s->lock != file)
929 return -EACCES;
930
David Schleefed9eccb2008-11-04 20:29:31 -0800931 async = s->async;
932
933 if (!async) {
934 DPRINTK("subdevice does not have async capability\n");
935 bi.buf_write_ptr = 0;
936 bi.buf_read_ptr = 0;
937 bi.buf_write_count = 0;
938 bi.buf_read_count = 0;
Ian Abbott4772c012010-05-19 18:09:49 +0100939 bi.bytes_read = 0;
940 bi.bytes_written = 0;
David Schleefed9eccb2008-11-04 20:29:31 -0800941 goto copyback;
942 }
Ian Abbott53fa8272010-05-19 18:09:50 +0100943 if (!s->busy) {
944 bi.bytes_read = 0;
945 bi.bytes_written = 0;
946 goto copyback_position;
947 }
948 if (s->busy != file)
949 return -EACCES;
David Schleefed9eccb2008-11-04 20:29:31 -0800950
951 if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
952 bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
953 comedi_buf_read_free(async, bi.bytes_read);
954
H Hartley Sweeten9682e282012-12-19 15:44:24 -0700955 if (comedi_is_subdevice_idle(s) &&
956 async->buf_write_count == async->buf_read_count) {
David Schleefed9eccb2008-11-04 20:29:31 -0800957 do_become_nonbusy(dev, s);
958 }
959 }
960
961 if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
962 bi.bytes_written =
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800963 comedi_buf_write_alloc(async, bi.bytes_written);
David Schleefed9eccb2008-11-04 20:29:31 -0800964 comedi_buf_write_free(async, bi.bytes_written);
965 }
966
Ian Abbott53fa8272010-05-19 18:09:50 +0100967copyback_position:
David Schleefed9eccb2008-11-04 20:29:31 -0800968 bi.buf_write_count = async->buf_write_count;
969 bi.buf_write_ptr = async->buf_write_ptr;
970 bi.buf_read_count = async->buf_read_count;
971 bi.buf_read_ptr = async->buf_read_ptr;
972
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800973copyback:
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700974 if (copy_to_user(arg, &bi, sizeof(bi)))
David Schleefed9eccb2008-11-04 20:29:31 -0800975 return -EFAULT;
976
977 return 0;
978}
979
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530980static int check_insn_config_length(struct comedi_insn *insn,
981 unsigned int *data)
David Schleefed9eccb2008-11-04 20:29:31 -0800982{
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800983 if (insn->n < 1)
984 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -0800985
986 switch (data[0]) {
987 case INSN_CONFIG_DIO_OUTPUT:
988 case INSN_CONFIG_DIO_INPUT:
989 case INSN_CONFIG_DISARM:
990 case INSN_CONFIG_RESET:
991 if (insn->n == 1)
992 return 0;
993 break;
994 case INSN_CONFIG_ARM:
995 case INSN_CONFIG_DIO_QUERY:
996 case INSN_CONFIG_BLOCK_SIZE:
997 case INSN_CONFIG_FILTER:
998 case INSN_CONFIG_SERIAL_CLOCK:
999 case INSN_CONFIG_BIDIRECTIONAL_DATA:
1000 case INSN_CONFIG_ALT_SOURCE:
1001 case INSN_CONFIG_SET_COUNTER_MODE:
1002 case INSN_CONFIG_8254_READ_STATUS:
1003 case INSN_CONFIG_SET_ROUTING:
1004 case INSN_CONFIG_GET_ROUTING:
1005 case INSN_CONFIG_GET_PWM_STATUS:
1006 case INSN_CONFIG_PWM_SET_PERIOD:
1007 case INSN_CONFIG_PWM_GET_PERIOD:
1008 if (insn->n == 2)
1009 return 0;
1010 break;
1011 case INSN_CONFIG_SET_GATE_SRC:
1012 case INSN_CONFIG_GET_GATE_SRC:
1013 case INSN_CONFIG_SET_CLOCK_SRC:
1014 case INSN_CONFIG_GET_CLOCK_SRC:
1015 case INSN_CONFIG_SET_OTHER_SRC:
1016 case INSN_CONFIG_GET_COUNTER_STATUS:
1017 case INSN_CONFIG_PWM_SET_H_BRIDGE:
1018 case INSN_CONFIG_PWM_GET_H_BRIDGE:
1019 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
1020 if (insn->n == 3)
1021 return 0;
1022 break;
1023 case INSN_CONFIG_PWM_OUTPUT:
1024 case INSN_CONFIG_ANALOG_TRIG:
1025 if (insn->n == 5)
1026 return 0;
1027 break;
Ian Abbottb0a2b6d2012-11-14 11:22:57 +00001028 case INSN_CONFIG_DIGITAL_TRIG:
1029 if (insn->n == 6)
1030 return 0;
1031 break;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301032 /* by default we allow the insn since we don't have checks for
1033 * all possible cases yet */
David Schleefed9eccb2008-11-04 20:29:31 -08001034 default:
Ian Abbott4f870fe2012-08-16 14:38:05 +01001035 pr_warn("comedi: No check for data length of config insn id %i is implemented.\n",
1036 data[0]);
1037 pr_warn("comedi: Add a check to %s in %s.\n",
1038 __func__, __FILE__);
1039 pr_warn("comedi: Assuming n=%i is correct.\n", insn->n);
David Schleefed9eccb2008-11-04 20:29:31 -08001040 return 0;
David Schleefed9eccb2008-11-04 20:29:31 -08001041 }
1042 return -EINVAL;
1043}
1044
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301045static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
1046 unsigned int *data, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001047{
Bill Pemberton34c43922009-03-16 22:05:14 -04001048 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001049 int ret = 0;
1050 int i;
1051
1052 if (insn->insn & INSN_MASK_SPECIAL) {
1053 /* a non-subdevice instruction */
1054
1055 switch (insn->insn) {
1056 case INSN_GTOD:
1057 {
1058 struct timeval tv;
1059
1060 if (insn->n != 2) {
1061 ret = -EINVAL;
1062 break;
1063 }
1064
1065 do_gettimeofday(&tv);
1066 data[0] = tv.tv_sec;
1067 data[1] = tv.tv_usec;
1068 ret = 2;
1069
1070 break;
1071 }
1072 case INSN_WAIT:
1073 if (insn->n != 1 || data[0] >= 100000) {
1074 ret = -EINVAL;
1075 break;
1076 }
1077 udelay(data[0] / 1000);
1078 ret = 1;
1079 break;
1080 case INSN_INTTRIG:
1081 if (insn->n != 1) {
1082 ret = -EINVAL;
1083 break;
1084 }
1085 if (insn->subdev >= dev->n_subdevices) {
1086 DPRINTK("%d not usable subdevice\n",
1087 insn->subdev);
1088 ret = -EINVAL;
1089 break;
1090 }
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001091 s = &dev->subdevices[insn->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001092 if (!s->async) {
1093 DPRINTK("no async\n");
1094 ret = -EINVAL;
1095 break;
1096 }
1097 if (!s->async->inttrig) {
1098 DPRINTK("no inttrig\n");
1099 ret = -EAGAIN;
1100 break;
1101 }
Ian Abbott5d06e3d2012-09-18 19:46:58 +01001102 ret = s->async->inttrig(dev, s, data[0]);
David Schleefed9eccb2008-11-04 20:29:31 -08001103 if (ret >= 0)
1104 ret = 1;
1105 break;
1106 default:
1107 DPRINTK("invalid insn\n");
1108 ret = -EINVAL;
1109 break;
1110 }
1111 } else {
1112 /* a subdevice instruction */
Bill Pemberton790c5542009-03-16 22:05:02 -04001113 unsigned int maxdata;
David Schleefed9eccb2008-11-04 20:29:31 -08001114
1115 if (insn->subdev >= dev->n_subdevices) {
1116 DPRINTK("subdevice %d out of range\n", insn->subdev);
1117 ret = -EINVAL;
1118 goto out;
1119 }
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001120 s = &dev->subdevices[insn->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001121
1122 if (s->type == COMEDI_SUBD_UNUSED) {
1123 DPRINTK("%d not usable subdevice\n", insn->subdev);
1124 ret = -EIO;
1125 goto out;
1126 }
1127
1128 /* are we locked? (ioctl lock) */
1129 if (s->lock && s->lock != file) {
1130 DPRINTK("device locked\n");
1131 ret = -EACCES;
1132 goto out;
1133 }
1134
Greg Kroah-Hartman0fd0ca72010-05-01 12:33:17 -07001135 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001136 if (ret < 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001137 ret = -EINVAL;
1138 DPRINTK("bad chanspec\n");
1139 goto out;
1140 }
1141
1142 if (s->busy) {
1143 ret = -EBUSY;
1144 goto out;
1145 }
1146 /* This looks arbitrary. It is. */
1147 s->busy = &parse_insn;
1148 switch (insn->insn) {
1149 case INSN_READ:
1150 ret = s->insn_read(dev, s, insn, data);
1151 break;
1152 case INSN_WRITE:
1153 maxdata = s->maxdata_list
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001154 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1155 : s->maxdata;
David Schleefed9eccb2008-11-04 20:29:31 -08001156 for (i = 0; i < insn->n; ++i) {
1157 if (data[i] > maxdata) {
1158 ret = -EINVAL;
1159 DPRINTK("bad data value(s)\n");
1160 break;
1161 }
1162 }
1163 if (ret == 0)
1164 ret = s->insn_write(dev, s, insn, data);
1165 break;
1166 case INSN_BITS:
1167 if (insn->n != 2) {
1168 ret = -EINVAL;
Ian Abbott2f644cc2011-01-18 17:44:33 +00001169 } else {
1170 /* Most drivers ignore the base channel in
1171 * insn->chanspec. Fix this here if
1172 * the subdevice has <= 32 channels. */
1173 unsigned int shift;
1174 unsigned int orig_mask;
1175
1176 orig_mask = data[0];
1177 if (s->n_chan <= 32) {
1178 shift = CR_CHAN(insn->chanspec);
1179 if (shift > 0) {
1180 insn->chanspec = 0;
1181 data[0] <<= shift;
1182 data[1] <<= shift;
1183 }
1184 } else
1185 shift = 0;
1186 ret = s->insn_bits(dev, s, insn, data);
1187 data[0] = orig_mask;
1188 if (shift > 0)
1189 data[1] >>= shift;
David Schleefed9eccb2008-11-04 20:29:31 -08001190 }
David Schleefed9eccb2008-11-04 20:29:31 -08001191 break;
1192 case INSN_CONFIG:
1193 ret = check_insn_config_length(insn, data);
1194 if (ret)
1195 break;
1196 ret = s->insn_config(dev, s, insn, data);
1197 break;
1198 default:
1199 ret = -EINVAL;
1200 break;
1201 }
1202
1203 s->busy = NULL;
1204 }
1205
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001206out:
David Schleefed9eccb2008-11-04 20:29:31 -08001207 return ret;
1208}
1209
1210/*
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001211 * COMEDI_INSNLIST
1212 * synchronous instructions
1213 *
1214 * arg:
1215 * pointer to sync cmd structure
1216 *
1217 * reads:
1218 * sync cmd struct at arg
1219 * instruction list
1220 * data (for writes)
1221 *
1222 * writes:
1223 * data (for reads)
1224 */
1225/* arbitrary limits */
1226#define MAX_SAMPLES 256
1227static int do_insnlist_ioctl(struct comedi_device *dev,
1228 struct comedi_insnlist __user *arg, void *file)
1229{
1230 struct comedi_insnlist insnlist;
1231 struct comedi_insn *insns = NULL;
1232 unsigned int *data = NULL;
1233 int i = 0;
1234 int ret = 0;
1235
1236 if (copy_from_user(&insnlist, arg, sizeof(insnlist)))
1237 return -EFAULT;
1238
1239 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
1240 if (!data) {
1241 DPRINTK("kmalloc failed\n");
1242 ret = -ENOMEM;
1243 goto error;
1244 }
1245
1246 insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
1247 if (!insns) {
1248 DPRINTK("kmalloc failed\n");
1249 ret = -ENOMEM;
1250 goto error;
1251 }
1252
1253 if (copy_from_user(insns, insnlist.insns,
1254 sizeof(*insns) * insnlist.n_insns)) {
1255 DPRINTK("copy_from_user failed\n");
1256 ret = -EFAULT;
1257 goto error;
1258 }
1259
1260 for (i = 0; i < insnlist.n_insns; i++) {
1261 if (insns[i].n > MAX_SAMPLES) {
1262 DPRINTK("number of samples too large\n");
1263 ret = -EINVAL;
1264 goto error;
1265 }
1266 if (insns[i].insn & INSN_MASK_WRITE) {
1267 if (copy_from_user(data, insns[i].data,
1268 insns[i].n * sizeof(unsigned int))) {
1269 DPRINTK("copy_from_user failed\n");
1270 ret = -EFAULT;
1271 goto error;
1272 }
1273 }
1274 ret = parse_insn(dev, insns + i, data, file);
1275 if (ret < 0)
1276 goto error;
1277 if (insns[i].insn & INSN_MASK_READ) {
1278 if (copy_to_user(insns[i].data, data,
1279 insns[i].n * sizeof(unsigned int))) {
1280 DPRINTK("copy_to_user failed\n");
1281 ret = -EFAULT;
1282 goto error;
1283 }
1284 }
1285 if (need_resched())
1286 schedule();
1287 }
1288
1289error:
1290 kfree(insns);
1291 kfree(data);
1292
1293 if (ret < 0)
1294 return ret;
1295 return i;
1296}
1297
1298/*
Pieter De Praetere20617f22010-03-10 09:47:44 +01001299 * COMEDI_INSN
1300 * synchronous instructions
David Schleefed9eccb2008-11-04 20:29:31 -08001301 *
Pieter De Praetere20617f22010-03-10 09:47:44 +01001302 * arg:
1303 * pointer to insn
David Schleefed9eccb2008-11-04 20:29:31 -08001304 *
Pieter De Praetere20617f22010-03-10 09:47:44 +01001305 * reads:
1306 * struct comedi_insn struct at arg
1307 * data (for writes)
David Schleefed9eccb2008-11-04 20:29:31 -08001308 *
Pieter De Praetere20617f22010-03-10 09:47:44 +01001309 * writes:
1310 * data (for reads)
David Schleefed9eccb2008-11-04 20:29:31 -08001311 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001312static int do_insn_ioctl(struct comedi_device *dev,
1313 struct comedi_insn __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001314{
Bill Pemberton90035c02009-03-16 22:05:53 -04001315 struct comedi_insn insn;
Bill Pemberton790c5542009-03-16 22:05:02 -04001316 unsigned int *data = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001317 int ret = 0;
1318
Bill Pemberton790c5542009-03-16 22:05:02 -04001319 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
David Schleefed9eccb2008-11-04 20:29:31 -08001320 if (!data) {
1321 ret = -ENOMEM;
1322 goto error;
1323 }
1324
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001325 if (copy_from_user(&insn, arg, sizeof(insn))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001326 ret = -EFAULT;
1327 goto error;
1328 }
1329
1330 /* This is where the behavior of insn and insnlist deviate. */
1331 if (insn.n > MAX_SAMPLES)
1332 insn.n = MAX_SAMPLES;
1333 if (insn.insn & INSN_MASK_WRITE) {
Mark21fe2ee2010-05-13 17:44:39 +08001334 if (copy_from_user(data,
1335 insn.data,
1336 insn.n * sizeof(unsigned int))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001337 ret = -EFAULT;
1338 goto error;
1339 }
1340 }
1341 ret = parse_insn(dev, &insn, data, file);
1342 if (ret < 0)
1343 goto error;
1344 if (insn.insn & INSN_MASK_READ) {
Mark21fe2ee2010-05-13 17:44:39 +08001345 if (copy_to_user(insn.data,
1346 data,
1347 insn.n * sizeof(unsigned int))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001348 ret = -EFAULT;
1349 goto error;
1350 }
1351 }
1352 ret = insn.n;
1353
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001354error:
1355 kfree(data);
David Schleefed9eccb2008-11-04 20:29:31 -08001356
1357 return ret;
1358}
1359
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001360static int do_cmd_ioctl(struct comedi_device *dev,
H Hartley Sweetencbe01f72012-09-18 11:41:54 -07001361 struct comedi_cmd __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001362{
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001363 struct comedi_cmd cmd;
Bill Pemberton34c43922009-03-16 22:05:14 -04001364 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04001365 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -08001366 int ret = 0;
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001367 unsigned int __user *user_chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001368
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001369 if (copy_from_user(&cmd, arg, sizeof(cmd))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001370 DPRINTK("bad cmd address\n");
1371 return -EFAULT;
1372 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001373 /* save user's chanlist pointer so it can be restored later */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001374 user_chanlist = (unsigned int __user *)cmd.chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001375
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001376 if (cmd.subdev >= dev->n_subdevices) {
1377 DPRINTK("%d no such subdevice\n", cmd.subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001378 return -ENODEV;
1379 }
1380
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001381 s = &dev->subdevices[cmd.subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001382 async = s->async;
1383
1384 if (s->type == COMEDI_SUBD_UNUSED) {
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001385 DPRINTK("%d not valid subdevice\n", cmd.subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001386 return -EIO;
1387 }
1388
1389 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1390 DPRINTK("subdevice %i does not support commands\n",
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001391 cmd.subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001392 return -EIO;
1393 }
1394
1395 /* are we locked? (ioctl lock) */
1396 if (s->lock && s->lock != file) {
1397 DPRINTK("subdevice locked\n");
1398 return -EACCES;
1399 }
1400
1401 /* are we busy? */
1402 if (s->busy) {
1403 DPRINTK("subdevice busy\n");
1404 return -EBUSY;
1405 }
David Schleefed9eccb2008-11-04 20:29:31 -08001406
1407 /* make sure channel/gain list isn't too long */
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001408 if (cmd.chanlist_len > s->len_chanlist) {
David Schleefed9eccb2008-11-04 20:29:31 -08001409 DPRINTK("channel/gain list too long %u > %d\n",
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001410 cmd.chanlist_len, s->len_chanlist);
Ian Abbott4b18f082013-07-05 16:49:34 +01001411 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001412 }
1413
1414 /* make sure channel/gain list isn't too short */
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001415 if (cmd.chanlist_len < 1) {
David Schleefed9eccb2008-11-04 20:29:31 -08001416 DPRINTK("channel/gain list too short %u < 1\n",
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001417 cmd.chanlist_len);
Ian Abbott4b18f082013-07-05 16:49:34 +01001418 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001419 }
1420
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001421 async->cmd = cmd;
David Schleefed9eccb2008-11-04 20:29:31 -08001422 async->cmd.data = NULL;
1423 /* load channel/gain list */
Teodora Balutaf0c80e42013-10-29 00:09:18 +02001424 async->cmd.chanlist = memdup_user(user_chanlist,
1425 async->cmd.chanlist_len * sizeof(int));
1426 if (IS_ERR(async->cmd.chanlist)) {
1427 ret = PTR_ERR(async->cmd.chanlist);
1428 DPRINTK("memdup_user failed with code %d\n", ret);
David Schleefed9eccb2008-11-04 20:29:31 -08001429 goto cleanup;
1430 }
1431
1432 /* make sure each element in channel/gain list is valid */
Mark21fe2ee2010-05-13 17:44:39 +08001433 ret = comedi_check_chanlist(s,
1434 async->cmd.chanlist_len,
1435 async->cmd.chanlist);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001436 if (ret < 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001437 DPRINTK("bad chanlist\n");
1438 goto cleanup;
1439 }
1440
1441 ret = s->do_cmdtest(dev, s, &async->cmd);
1442
1443 if (async->cmd.flags & TRIG_BOGUS || ret) {
1444 DPRINTK("test returned %d\n", ret);
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001445 cmd = async->cmd;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001446 /* restore chanlist pointer before copying back */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001447 cmd.chanlist = (unsigned int __force *)user_chanlist;
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001448 cmd.data = NULL;
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001449 if (copy_to_user(arg, &cmd, sizeof(cmd))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001450 DPRINTK("fault writing cmd\n");
1451 ret = -EFAULT;
1452 goto cleanup;
1453 }
1454 ret = -EAGAIN;
1455 goto cleanup;
1456 }
1457
1458 if (!async->prealloc_bufsz) {
1459 ret = -ENOMEM;
1460 DPRINTK("no buffer (?)\n");
1461 goto cleanup;
1462 }
1463
H Hartley Sweeten61c9fb02013-01-09 13:27:07 -07001464 comedi_buf_reset(async);
David Schleefed9eccb2008-11-04 20:29:31 -08001465
1466 async->cb_mask =
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001467 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1468 COMEDI_CB_OVERFLOW;
1469 if (async->cmd.flags & TRIG_WAKE_EOS)
David Schleefed9eccb2008-11-04 20:29:31 -08001470 async->cb_mask |= COMEDI_CB_EOS;
David Schleefed9eccb2008-11-04 20:29:31 -08001471
Ian Abbott67aa4ac2013-10-07 15:51:58 +01001472 comedi_set_subdevice_runflags(s, SRF_USER | SRF_ERROR | SRF_RUNNING,
1473 SRF_USER | SRF_RUNNING);
David Schleefed9eccb2008-11-04 20:29:31 -08001474
Ian Abbott4b18f082013-07-05 16:49:34 +01001475 /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
1476 * comedi_read() or comedi_write() */
1477 s->busy = file;
David Schleefed9eccb2008-11-04 20:29:31 -08001478 ret = s->do_cmd(dev, s);
1479 if (ret == 0)
1480 return 0;
1481
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001482cleanup:
David Schleefed9eccb2008-11-04 20:29:31 -08001483 do_become_nonbusy(dev, s);
1484
1485 return ret;
1486}
1487
1488/*
1489 COMEDI_CMDTEST
1490 command testing ioctl
1491
1492 arg:
1493 pointer to cmd structure
1494
1495 reads:
1496 cmd structure at arg
1497 channel/range list
1498
1499 writes:
1500 modified cmd structure at arg
1501
1502*/
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001503static int do_cmdtest_ioctl(struct comedi_device *dev,
1504 struct comedi_cmd __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001505{
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001506 struct comedi_cmd cmd;
Bill Pemberton34c43922009-03-16 22:05:14 -04001507 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001508 int ret = 0;
1509 unsigned int *chanlist = NULL;
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001510 unsigned int __user *user_chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001511
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001512 if (copy_from_user(&cmd, arg, sizeof(cmd))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001513 DPRINTK("bad cmd address\n");
1514 return -EFAULT;
1515 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001516 /* save user's chanlist pointer so it can be restored later */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001517 user_chanlist = (unsigned int __user *)cmd.chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001518
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001519 if (cmd.subdev >= dev->n_subdevices) {
1520 DPRINTK("%d no such subdevice\n", cmd.subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001521 return -ENODEV;
1522 }
1523
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001524 s = &dev->subdevices[cmd.subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001525 if (s->type == COMEDI_SUBD_UNUSED) {
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001526 DPRINTK("%d not valid subdevice\n", cmd.subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001527 return -EIO;
1528 }
1529
1530 if (!s->do_cmd || !s->do_cmdtest) {
1531 DPRINTK("subdevice %i does not support commands\n",
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001532 cmd.subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001533 return -EIO;
1534 }
1535
1536 /* make sure channel/gain list isn't too long */
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001537 if (cmd.chanlist_len > s->len_chanlist) {
David Schleefed9eccb2008-11-04 20:29:31 -08001538 DPRINTK("channel/gain list too long %d > %d\n",
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001539 cmd.chanlist_len, s->len_chanlist);
David Schleefed9eccb2008-11-04 20:29:31 -08001540 ret = -EINVAL;
1541 goto cleanup;
1542 }
1543
1544 /* load channel/gain list */
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001545 if (cmd.chanlist) {
Teodora Balutaf0c80e42013-10-29 00:09:18 +02001546 chanlist = memdup_user(user_chanlist,
1547 cmd.chanlist_len * sizeof(int));
1548 if (IS_ERR(chanlist)) {
1549 ret = PTR_ERR(chanlist);
1550 DPRINTK("memdup_user exited with code %d", ret);
David Schleefed9eccb2008-11-04 20:29:31 -08001551 goto cleanup;
1552 }
1553
1554 /* make sure each element in channel/gain list is valid */
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001555 ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001556 if (ret < 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001557 DPRINTK("bad chanlist\n");
1558 goto cleanup;
1559 }
1560
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001561 cmd.chanlist = chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001562 }
1563
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001564 ret = s->do_cmdtest(dev, s, &cmd);
David Schleefed9eccb2008-11-04 20:29:31 -08001565
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001566 /* restore chanlist pointer before copying back */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001567 cmd.chanlist = (unsigned int __force *)user_chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001568
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001569 if (copy_to_user(arg, &cmd, sizeof(cmd))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001570 DPRINTK("bad cmd address\n");
1571 ret = -EFAULT;
1572 goto cleanup;
1573 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001574cleanup:
1575 kfree(chanlist);
David Schleefed9eccb2008-11-04 20:29:31 -08001576
1577 return ret;
1578}
1579
1580/*
1581 COMEDI_LOCK
1582 lock subdevice
1583
1584 arg:
1585 subdevice number
1586
1587 reads:
1588 none
1589
1590 writes:
1591 none
1592
1593*/
1594
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301595static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1596 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001597{
1598 int ret = 0;
1599 unsigned long flags;
Bill Pemberton34c43922009-03-16 22:05:14 -04001600 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001601
1602 if (arg >= dev->n_subdevices)
1603 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001604 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001605
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001606 spin_lock_irqsave(&s->spin_lock, flags);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001607 if (s->busy || s->lock)
David Schleefed9eccb2008-11-04 20:29:31 -08001608 ret = -EBUSY;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001609 else
David Schleefed9eccb2008-11-04 20:29:31 -08001610 s->lock = file;
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001611 spin_unlock_irqrestore(&s->spin_lock, flags);
David Schleefed9eccb2008-11-04 20:29:31 -08001612
Greg Dietschec5274ab2011-06-13 13:11:47 -05001613#if 0
David Schleefed9eccb2008-11-04 20:29:31 -08001614 if (ret < 0)
1615 return ret;
1616
David Schleefed9eccb2008-11-04 20:29:31 -08001617 if (s->lock_f)
1618 ret = s->lock_f(dev, s);
1619#endif
1620
1621 return ret;
1622}
1623
1624/*
1625 COMEDI_UNLOCK
1626 unlock subdevice
1627
1628 arg:
1629 subdevice number
1630
1631 reads:
1632 none
1633
1634 writes:
1635 none
1636
1637 This function isn't protected by the semaphore, since
1638 we already own the lock.
1639*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301640static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1641 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001642{
Bill Pemberton34c43922009-03-16 22:05:14 -04001643 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001644
1645 if (arg >= dev->n_subdevices)
1646 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001647 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001648
1649 if (s->busy)
1650 return -EBUSY;
1651
1652 if (s->lock && s->lock != file)
1653 return -EACCES;
1654
1655 if (s->lock == file) {
1656#if 0
1657 if (s->unlock)
1658 s->unlock(dev, s);
1659#endif
1660
1661 s->lock = NULL;
1662 }
1663
1664 return 0;
1665}
1666
1667/*
1668 COMEDI_CANCEL
1669 cancel acquisition ioctl
1670
1671 arg:
1672 subdevice number
1673
1674 reads:
1675 nothing
1676
1677 writes:
1678 nothing
1679
1680*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301681static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1682 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001683{
Bill Pemberton34c43922009-03-16 22:05:14 -04001684 struct comedi_subdevice *s;
Ian Abbott69acbaa2013-07-08 13:36:19 +01001685 int ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001686
1687 if (arg >= dev->n_subdevices)
1688 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001689 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001690 if (s->async == NULL)
1691 return -EINVAL;
1692
1693 if (s->lock && s->lock != file)
1694 return -EACCES;
1695
1696 if (!s->busy)
1697 return 0;
1698
1699 if (s->busy != file)
1700 return -EBUSY;
1701
Ian Abbott69acbaa2013-07-08 13:36:19 +01001702 ret = do_cancel(dev, s);
1703 if (comedi_get_subdevice_runflags(s) & SRF_USER)
1704 wake_up_interruptible(&s->async->wait_head);
1705
1706 return ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001707}
1708
1709/*
1710 COMEDI_POLL ioctl
1711 instructs driver to synchronize buffers
1712
1713 arg:
1714 subdevice number
1715
1716 reads:
1717 nothing
1718
1719 writes:
1720 nothing
1721
1722*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301723static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1724 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001725{
Bill Pemberton34c43922009-03-16 22:05:14 -04001726 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001727
1728 if (arg >= dev->n_subdevices)
1729 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001730 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001731
1732 if (s->lock && s->lock != file)
1733 return -EACCES;
1734
1735 if (!s->busy)
1736 return 0;
1737
1738 if (s->busy != file)
1739 return -EBUSY;
1740
1741 if (s->poll)
1742 return s->poll(dev, s);
1743
1744 return -EINVAL;
1745}
1746
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001747static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
1748 unsigned long arg)
1749{
Al Viro6131ffa2013-02-27 16:59:05 -05001750 const unsigned minor = iminor(file_inode(file));
Ian Abbott5e04c252013-04-04 14:59:11 +01001751 struct comedi_device *dev = comedi_dev_from_minor(minor);
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001752 int rc;
1753
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07001754 if (!dev)
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001755 return -ENODEV;
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001756
1757 mutex_lock(&dev->mutex);
1758
1759 /* Device config is special, because it must work on
1760 * an unconfigured device. */
1761 if (cmd == COMEDI_DEVCONFIG) {
Ian Abbott754ab5c2013-01-28 16:14:31 +00001762 if (minor >= COMEDI_NUM_BOARD_MINORS) {
1763 /* Device config not appropriate on non-board minors. */
1764 rc = -ENOTTY;
1765 goto done;
1766 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001767 rc = do_devconfig_ioctl(dev,
1768 (struct comedi_devconfig __user *)arg);
Ian Abbott8ab4ed62013-04-04 14:58:54 +01001769 if (rc == 0) {
1770 if (arg == 0 &&
1771 dev->minor >= comedi_num_legacy_minors) {
1772 /* Successfully unconfigured a dynamically
1773 * allocated device. Try and remove it. */
Ian Abbottdb210da2013-04-04 14:59:18 +01001774 if (comedi_clear_board_dev(dev)) {
Ian Abbott8ab4ed62013-04-04 14:58:54 +01001775 mutex_unlock(&dev->mutex);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01001776 comedi_free_board_dev(dev);
Ian Abbott8ab4ed62013-04-04 14:58:54 +01001777 return rc;
1778 }
1779 }
1780 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001781 goto done;
1782 }
1783
1784 if (!dev->attached) {
1785 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
1786 rc = -ENODEV;
1787 goto done;
1788 }
1789
1790 switch (cmd) {
1791 case COMEDI_BUFCONFIG:
1792 rc = do_bufconfig_ioctl(dev,
1793 (struct comedi_bufconfig __user *)arg);
1794 break;
1795 case COMEDI_DEVINFO:
1796 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
1797 file);
1798 break;
1799 case COMEDI_SUBDINFO:
1800 rc = do_subdinfo_ioctl(dev,
1801 (struct comedi_subdinfo __user *)arg,
1802 file);
1803 break;
1804 case COMEDI_CHANINFO:
1805 rc = do_chaninfo_ioctl(dev, (void __user *)arg);
1806 break;
1807 case COMEDI_RANGEINFO:
1808 rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
1809 break;
1810 case COMEDI_BUFINFO:
1811 rc = do_bufinfo_ioctl(dev,
1812 (struct comedi_bufinfo __user *)arg,
1813 file);
1814 break;
1815 case COMEDI_LOCK:
1816 rc = do_lock_ioctl(dev, arg, file);
1817 break;
1818 case COMEDI_UNLOCK:
1819 rc = do_unlock_ioctl(dev, arg, file);
1820 break;
1821 case COMEDI_CANCEL:
1822 rc = do_cancel_ioctl(dev, arg, file);
1823 break;
1824 case COMEDI_CMD:
1825 rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
1826 break;
1827 case COMEDI_CMDTEST:
1828 rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
1829 file);
1830 break;
1831 case COMEDI_INSNLIST:
1832 rc = do_insnlist_ioctl(dev,
1833 (struct comedi_insnlist __user *)arg,
1834 file);
1835 break;
1836 case COMEDI_INSN:
1837 rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
1838 file);
1839 break;
1840 case COMEDI_POLL:
1841 rc = do_poll_ioctl(dev, arg, file);
1842 break;
1843 default:
1844 rc = -ENOTTY;
1845 break;
1846 }
1847
1848done:
1849 mutex_unlock(&dev->mutex);
1850 return rc;
1851}
1852
Federico Vagadf30b212011-10-29 09:45:39 +02001853static void comedi_vm_open(struct vm_area_struct *area)
1854{
1855 struct comedi_async *async;
1856 struct comedi_device *dev;
1857
1858 async = area->vm_private_data;
1859 dev = async->subdevice->device;
1860
1861 mutex_lock(&dev->mutex);
1862 async->mmap_count++;
1863 mutex_unlock(&dev->mutex);
1864}
1865
1866static void comedi_vm_close(struct vm_area_struct *area)
David Schleefed9eccb2008-11-04 20:29:31 -08001867{
Bill Pembertond1636792009-03-16 22:05:20 -04001868 struct comedi_async *async;
Bill Pemberton71b5f4f2009-03-16 22:05:08 -04001869 struct comedi_device *dev;
David Schleefed9eccb2008-11-04 20:29:31 -08001870
1871 async = area->vm_private_data;
1872 dev = async->subdevice->device;
1873
1874 mutex_lock(&dev->mutex);
1875 async->mmap_count--;
1876 mutex_unlock(&dev->mutex);
1877}
1878
1879static struct vm_operations_struct comedi_vm_ops = {
Federico Vagadf30b212011-10-29 09:45:39 +02001880 .open = comedi_vm_open,
1881 .close = comedi_vm_close,
David Schleefed9eccb2008-11-04 20:29:31 -08001882};
1883
1884static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1885{
Al Viro6131ffa2013-02-27 16:59:05 -05001886 const unsigned minor = iminor(file_inode(file));
Ian Abbott5e04c252013-04-04 14:59:11 +01001887 struct comedi_device *dev = comedi_dev_from_minor(minor);
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001888 struct comedi_subdevice *s;
1889 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -08001890 unsigned long start = vma->vm_start;
1891 unsigned long size;
1892 int n_pages;
1893 int i;
1894 int retval;
Bernd Porr3ffab422011-11-08 21:23:03 +00001895
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001896 if (!dev)
Florian Schmaus70fe7422011-12-14 14:23:24 +01001897 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08001898
1899 mutex_lock(&dev->mutex);
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001900
David Schleefed9eccb2008-11-04 20:29:31 -08001901 if (!dev->attached) {
1902 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1903 retval = -ENODEV;
1904 goto done;
1905 }
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001906
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001907 if (vma->vm_flags & VM_WRITE)
Ian Abbottda56fdc2013-04-04 14:59:10 +01001908 s = comedi_write_subdevice(dev, minor);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001909 else
Ian Abbottda56fdc2013-04-04 14:59:10 +01001910 s = comedi_read_subdevice(dev, minor);
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001911 if (!s) {
David Schleefed9eccb2008-11-04 20:29:31 -08001912 retval = -EINVAL;
1913 goto done;
1914 }
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001915
David Schleefed9eccb2008-11-04 20:29:31 -08001916 async = s->async;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001917 if (!async) {
David Schleefed9eccb2008-11-04 20:29:31 -08001918 retval = -EINVAL;
1919 goto done;
1920 }
1921
1922 if (vma->vm_pgoff != 0) {
1923 DPRINTK("comedi: mmap() offset must be 0.\n");
1924 retval = -EINVAL;
1925 goto done;
1926 }
1927
1928 size = vma->vm_end - vma->vm_start;
1929 if (size > async->prealloc_bufsz) {
1930 retval = -EFAULT;
1931 goto done;
1932 }
1933 if (size & (~PAGE_MASK)) {
1934 retval = -EFAULT;
1935 goto done;
1936 }
1937
1938 n_pages = size >> PAGE_SHIFT;
1939 for (i = 0; i < n_pages; ++i) {
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001940 struct comedi_buf_page *buf = &async->buf_page_list[i];
1941
David Schleefed9eccb2008-11-04 20:29:31 -08001942 if (remap_pfn_range(vma, start,
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001943 page_to_pfn(virt_to_page(buf->virt_addr)),
1944 PAGE_SIZE, PAGE_SHARED)) {
David Schleefed9eccb2008-11-04 20:29:31 -08001945 retval = -EAGAIN;
1946 goto done;
1947 }
1948 start += PAGE_SIZE;
1949 }
1950
1951 vma->vm_ops = &comedi_vm_ops;
1952 vma->vm_private_data = async;
1953
1954 async->mmap_count++;
1955
1956 retval = 0;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001957done:
David Schleefed9eccb2008-11-04 20:29:31 -08001958 mutex_unlock(&dev->mutex);
1959 return retval;
1960}
1961
Benedikt Bergenthal1ae50622012-04-16 12:40:22 +02001962static unsigned int comedi_poll(struct file *file, poll_table *wait)
David Schleefed9eccb2008-11-04 20:29:31 -08001963{
1964 unsigned int mask = 0;
Al Viro6131ffa2013-02-27 16:59:05 -05001965 const unsigned minor = iminor(file_inode(file));
Ian Abbott5e04c252013-04-04 14:59:11 +01001966 struct comedi_device *dev = comedi_dev_from_minor(minor);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001967 struct comedi_subdevice *s;
Bernd Porr3ffab422011-11-08 21:23:03 +00001968
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001969 if (!dev)
Florian Schmaus70fe7422011-12-14 14:23:24 +01001970 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08001971
1972 mutex_lock(&dev->mutex);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001973
David Schleefed9eccb2008-11-04 20:29:31 -08001974 if (!dev->attached) {
1975 DPRINTK("no driver configured on comedi%i\n", dev->minor);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001976 goto done;
David Schleefed9eccb2008-11-04 20:29:31 -08001977 }
1978
Ian Abbottda56fdc2013-04-04 14:59:10 +01001979 s = comedi_read_subdevice(dev, minor);
Ian Abbottcc400e12013-02-05 12:50:40 +00001980 if (s && s->async) {
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001981 poll_wait(file, &s->async->wait_head, wait);
H Hartley Sweetenf0124632012-12-19 15:43:18 -07001982 if (!s->busy || !comedi_is_subdevice_running(s) ||
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001983 comedi_buf_read_n_available(s->async) > 0)
David Schleefed9eccb2008-11-04 20:29:31 -08001984 mask |= POLLIN | POLLRDNORM;
David Schleefed9eccb2008-11-04 20:29:31 -08001985 }
1986
Ian Abbottda56fdc2013-04-04 14:59:10 +01001987 s = comedi_write_subdevice(dev, minor);
Ian Abbottcc400e12013-02-05 12:50:40 +00001988 if (s && s->async) {
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001989 unsigned int bps = bytes_per_sample(s->async->subdevice);
1990
1991 poll_wait(file, &s->async->wait_head, wait);
1992 comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
H Hartley Sweetenf0124632012-12-19 15:43:18 -07001993 if (!s->busy || !comedi_is_subdevice_running(s) ||
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001994 comedi_buf_write_n_allocated(s->async) >= bps)
1995 mask |= POLLOUT | POLLWRNORM;
1996 }
1997
1998done:
David Schleefed9eccb2008-11-04 20:29:31 -08001999 mutex_unlock(&dev->mutex);
2000 return mask;
2001}
2002
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07002003static ssize_t comedi_write(struct file *file, const char __user *buf,
2004 size_t nbytes, loff_t *offset)
David Schleefed9eccb2008-11-04 20:29:31 -08002005{
Bill Pemberton34c43922009-03-16 22:05:14 -04002006 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04002007 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -08002008 int n, m, count = 0, retval = 0;
2009 DECLARE_WAITQUEUE(wait, current);
Al Viro6131ffa2013-02-27 16:59:05 -05002010 const unsigned minor = iminor(file_inode(file));
Ian Abbott5e04c252013-04-04 14:59:11 +01002011 struct comedi_device *dev = comedi_dev_from_minor(minor);
Bernd Porr3ffab422011-11-08 21:23:03 +00002012
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002013 if (!dev)
Florian Schmaus70fe7422011-12-14 14:23:24 +01002014 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08002015
2016 if (!dev->attached) {
2017 DPRINTK("no driver configured on comedi%i\n", dev->minor);
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002018 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08002019 }
2020
Ian Abbottda56fdc2013-04-04 14:59:10 +01002021 s = comedi_write_subdevice(dev, minor);
Ian Abbottcc400e12013-02-05 12:50:40 +00002022 if (!s || !s->async)
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002023 return -EIO;
2024
David Schleefed9eccb2008-11-04 20:29:31 -08002025 async = s->async;
2026
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002027 if (!s->busy || !nbytes)
2028 return 0;
2029 if (s->busy != file)
2030 return -EACCES;
2031
David Schleefed9eccb2008-11-04 20:29:31 -08002032 add_wait_queue(&async->wait_head, &wait);
2033 while (nbytes > 0 && !retval) {
2034 set_current_state(TASK_INTERRUPTIBLE);
2035
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002036 if (!comedi_is_subdevice_running(s)) {
Ian Abbottd2611542010-05-19 17:22:41 +01002037 if (count == 0) {
Ian Abbott4b18f082013-07-05 16:49:34 +01002038 mutex_lock(&dev->mutex);
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002039 if (comedi_is_subdevice_in_error(s))
Ian Abbottd2611542010-05-19 17:22:41 +01002040 retval = -EPIPE;
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002041 else
Ian Abbottd2611542010-05-19 17:22:41 +01002042 retval = 0;
Ian Abbottd2611542010-05-19 17:22:41 +01002043 do_become_nonbusy(dev, s);
Ian Abbott4b18f082013-07-05 16:49:34 +01002044 mutex_unlock(&dev->mutex);
Ian Abbottd2611542010-05-19 17:22:41 +01002045 }
2046 break;
2047 }
2048
David Schleefed9eccb2008-11-04 20:29:31 -08002049 n = nbytes;
2050
2051 m = n;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002052 if (async->buf_write_ptr + m > async->prealloc_bufsz)
David Schleefed9eccb2008-11-04 20:29:31 -08002053 m = async->prealloc_bufsz - async->buf_write_ptr;
David Schleefed9eccb2008-11-04 20:29:31 -08002054 comedi_buf_write_alloc(async, async->prealloc_bufsz);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002055 if (m > comedi_buf_write_n_allocated(async))
David Schleefed9eccb2008-11-04 20:29:31 -08002056 m = comedi_buf_write_n_allocated(async);
David Schleefed9eccb2008-11-04 20:29:31 -08002057 if (m < n)
2058 n = m;
2059
2060 if (n == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08002061 if (file->f_flags & O_NONBLOCK) {
2062 retval = -EAGAIN;
2063 break;
2064 }
Federico Vaga6a9ce6b2011-10-29 09:47:39 +02002065 schedule();
David Schleefed9eccb2008-11-04 20:29:31 -08002066 if (signal_pending(current)) {
2067 retval = -ERESTARTSYS;
2068 break;
2069 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002070 if (!s->busy)
David Schleefed9eccb2008-11-04 20:29:31 -08002071 break;
David Schleefed9eccb2008-11-04 20:29:31 -08002072 if (s->busy != file) {
2073 retval = -EACCES;
2074 break;
2075 }
2076 continue;
2077 }
2078
2079 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002080 buf, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002081 if (m) {
2082 n -= m;
2083 retval = -EFAULT;
2084 }
2085 comedi_buf_write_free(async, n);
2086
2087 count += n;
2088 nbytes -= n;
2089
2090 buf += n;
2091 break; /* makes device work like a pipe */
2092 }
2093 set_current_state(TASK_RUNNING);
2094 remove_wait_queue(&async->wait_head, &wait);
2095
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002096 return count ? count : retval;
David Schleefed9eccb2008-11-04 20:29:31 -08002097}
2098
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07002099static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
Andrea Gelmini6705b682010-02-26 10:14:55 +01002100 loff_t *offset)
David Schleefed9eccb2008-11-04 20:29:31 -08002101{
Bill Pemberton34c43922009-03-16 22:05:14 -04002102 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04002103 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -08002104 int n, m, count = 0, retval = 0;
2105 DECLARE_WAITQUEUE(wait, current);
Al Viro6131ffa2013-02-27 16:59:05 -05002106 const unsigned minor = iminor(file_inode(file));
Ian Abbott5e04c252013-04-04 14:59:11 +01002107 struct comedi_device *dev = comedi_dev_from_minor(minor);
Bernd Porr3ffab422011-11-08 21:23:03 +00002108
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002109 if (!dev)
Florian Schmaus70fe7422011-12-14 14:23:24 +01002110 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08002111
2112 if (!dev->attached) {
2113 DPRINTK("no driver configured on comedi%i\n", dev->minor);
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002114 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08002115 }
2116
Ian Abbottda56fdc2013-04-04 14:59:10 +01002117 s = comedi_read_subdevice(dev, minor);
Ian Abbottcc400e12013-02-05 12:50:40 +00002118 if (!s || !s->async)
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002119 return -EIO;
2120
David Schleefed9eccb2008-11-04 20:29:31 -08002121 async = s->async;
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002122 if (!s->busy || !nbytes)
2123 return 0;
2124 if (s->busy != file)
2125 return -EACCES;
David Schleefed9eccb2008-11-04 20:29:31 -08002126
2127 add_wait_queue(&async->wait_head, &wait);
2128 while (nbytes > 0 && !retval) {
2129 set_current_state(TASK_INTERRUPTIBLE);
2130
2131 n = nbytes;
2132
2133 m = comedi_buf_read_n_available(async);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002134 /* printk("%d available\n",m); */
2135 if (async->buf_read_ptr + m > async->prealloc_bufsz)
David Schleefed9eccb2008-11-04 20:29:31 -08002136 m = async->prealloc_bufsz - async->buf_read_ptr;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002137 /* printk("%d contiguous\n",m); */
David Schleefed9eccb2008-11-04 20:29:31 -08002138 if (m < n)
2139 n = m;
2140
2141 if (n == 0) {
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002142 if (!comedi_is_subdevice_running(s)) {
Ian Abbott4b18f082013-07-05 16:49:34 +01002143 mutex_lock(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002144 do_become_nonbusy(dev, s);
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002145 if (comedi_is_subdevice_in_error(s))
David Schleefed9eccb2008-11-04 20:29:31 -08002146 retval = -EPIPE;
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002147 else
David Schleefed9eccb2008-11-04 20:29:31 -08002148 retval = 0;
Ian Abbott4b18f082013-07-05 16:49:34 +01002149 mutex_unlock(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002150 break;
2151 }
2152 if (file->f_flags & O_NONBLOCK) {
2153 retval = -EAGAIN;
2154 break;
2155 }
Federico Vaga6a9ce6b2011-10-29 09:47:39 +02002156 schedule();
David Schleefed9eccb2008-11-04 20:29:31 -08002157 if (signal_pending(current)) {
2158 retval = -ERESTARTSYS;
2159 break;
2160 }
David Schleefed9eccb2008-11-04 20:29:31 -08002161 if (!s->busy) {
2162 retval = 0;
2163 break;
2164 }
2165 if (s->busy != file) {
2166 retval = -EACCES;
2167 break;
2168 }
2169 continue;
2170 }
2171 m = copy_to_user(buf, async->prealloc_buf +
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002172 async->buf_read_ptr, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002173 if (m) {
2174 n -= m;
2175 retval = -EFAULT;
2176 }
2177
2178 comedi_buf_read_alloc(async, n);
2179 comedi_buf_read_free(async, n);
2180
2181 count += n;
2182 nbytes -= n;
2183
2184 buf += n;
2185 break; /* makes device work like a pipe */
2186 }
Ian Abbott4b18f082013-07-05 16:49:34 +01002187 if (comedi_is_subdevice_idle(s)) {
2188 mutex_lock(&dev->mutex);
2189 if (async->buf_read_count - async->buf_write_count == 0)
2190 do_become_nonbusy(dev, s);
2191 mutex_unlock(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002192 }
2193 set_current_state(TASK_RUNNING);
2194 remove_wait_queue(&async->wait_head, &wait);
2195
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002196 return count ? count : retval;
David Schleefed9eccb2008-11-04 20:29:31 -08002197}
2198
David Schleefed9eccb2008-11-04 20:29:31 -08002199static int comedi_open(struct inode *inode, struct file *file)
2200{
David Schleefed9eccb2008-11-04 20:29:31 -08002201 const unsigned minor = iminor(inode);
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002202 struct comedi_device *dev = comedi_dev_from_minor(minor);
Ian Abbott97920072009-02-09 16:51:38 +00002203
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002204 if (!dev) {
David Schleefed9eccb2008-11-04 20:29:31 -08002205 DPRINTK("invalid minor number\n");
2206 return -ENODEV;
2207 }
2208
2209 /* This is slightly hacky, but we want module autoloading
2210 * to work for root.
2211 * case: user opens device, attached -> ok
Ian Abbott13f12b52013-03-15 13:15:34 +00002212 * case: user opens device, unattached, !in_request_module -> autoload
2213 * case: user opens device, unattached, in_request_module -> fail
David Schleefed9eccb2008-11-04 20:29:31 -08002214 * case: root opens device, attached -> ok
Ian Abbott13f12b52013-03-15 13:15:34 +00002215 * case: root opens device, unattached, in_request_module -> ok
David Schleefed9eccb2008-11-04 20:29:31 -08002216 * (typically called from modprobe)
Ian Abbott13f12b52013-03-15 13:15:34 +00002217 * case: root opens device, unattached, !in_request_module -> autoload
David Schleefed9eccb2008-11-04 20:29:31 -08002218 *
2219 * The last could be changed to "-> ok", which would deny root
2220 * autoloading.
2221 */
2222 mutex_lock(&dev->mutex);
2223 if (dev->attached)
2224 goto ok;
Eric Parisa8f80e82009-08-13 09:44:51 -04002225 if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
David Schleefed9eccb2008-11-04 20:29:31 -08002226 DPRINTK("in request module\n");
2227 mutex_unlock(&dev->mutex);
2228 return -ENODEV;
2229 }
Eric Parisa8f80e82009-08-13 09:44:51 -04002230 if (capable(CAP_NET_ADMIN) && dev->in_request_module)
David Schleefed9eccb2008-11-04 20:29:31 -08002231 goto ok;
2232
Ian Abbott13f12b52013-03-15 13:15:34 +00002233 dev->in_request_module = true;
David Schleefed9eccb2008-11-04 20:29:31 -08002234
David Schleefed9eccb2008-11-04 20:29:31 -08002235#ifdef CONFIG_KMOD
2236 mutex_unlock(&dev->mutex);
Ian Abbott56d92c62009-02-09 16:32:12 +00002237 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
David Schleefed9eccb2008-11-04 20:29:31 -08002238 mutex_lock(&dev->mutex);
2239#endif
2240
Ian Abbott13f12b52013-03-15 13:15:34 +00002241 dev->in_request_module = false;
David Schleefed9eccb2008-11-04 20:29:31 -08002242
Eric Parisa8f80e82009-08-13 09:44:51 -04002243 if (!dev->attached && !capable(CAP_NET_ADMIN)) {
2244 DPRINTK("not attached and not CAP_NET_ADMIN\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002245 mutex_unlock(&dev->mutex);
2246 return -ENODEV;
2247 }
2248ok:
2249 __module_get(THIS_MODULE);
2250
2251 if (dev->attached) {
2252 if (!try_module_get(dev->driver->module)) {
2253 module_put(THIS_MODULE);
2254 mutex_unlock(&dev->mutex);
2255 return -ENOSYS;
2256 }
2257 }
2258
Ian Abbott3c17ba072010-05-19 14:10:00 +01002259 if (dev->attached && dev->use_count == 0 && dev->open) {
2260 int rc = dev->open(dev);
2261 if (rc < 0) {
2262 module_put(dev->driver->module);
2263 module_put(THIS_MODULE);
2264 mutex_unlock(&dev->mutex);
2265 return rc;
2266 }
2267 }
David Schleefed9eccb2008-11-04 20:29:31 -08002268
2269 dev->use_count++;
2270
2271 mutex_unlock(&dev->mutex);
2272
2273 return 0;
2274}
2275
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002276static int comedi_fasync(int fd, struct file *file, int on)
2277{
Al Viro6131ffa2013-02-27 16:59:05 -05002278 const unsigned minor = iminor(file_inode(file));
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002279 struct comedi_device *dev = comedi_dev_from_minor(minor);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002280
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002281 if (!dev)
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002282 return -ENODEV;
2283
2284 return fasync_helper(fd, file, on, &dev->async_queue);
2285}
2286
David Schleefed9eccb2008-11-04 20:29:31 -08002287static int comedi_close(struct inode *inode, struct file *file)
2288{
2289 const unsigned minor = iminor(inode);
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002290 struct comedi_device *dev = comedi_dev_from_minor(minor);
Bill Pemberton34c43922009-03-16 22:05:14 -04002291 struct comedi_subdevice *s = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08002292 int i;
Bernd Porr3ffab422011-11-08 21:23:03 +00002293
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002294 if (!dev)
Florian Schmaus70fe7422011-12-14 14:23:24 +01002295 return -ENODEV;
David Schleefed9eccb2008-11-04 20:29:31 -08002296
2297 mutex_lock(&dev->mutex);
2298
2299 if (dev->subdevices) {
2300 for (i = 0; i < dev->n_subdevices; i++) {
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07002301 s = &dev->subdevices[i];
David Schleefed9eccb2008-11-04 20:29:31 -08002302
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002303 if (s->busy == file)
David Schleefed9eccb2008-11-04 20:29:31 -08002304 do_cancel(dev, s);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002305 if (s->lock == file)
David Schleefed9eccb2008-11-04 20:29:31 -08002306 s->lock = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08002307 }
2308 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002309 if (dev->attached && dev->use_count == 1 && dev->close)
David Schleefed9eccb2008-11-04 20:29:31 -08002310 dev->close(dev);
David Schleefed9eccb2008-11-04 20:29:31 -08002311
2312 module_put(THIS_MODULE);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002313 if (dev->attached)
David Schleefed9eccb2008-11-04 20:29:31 -08002314 module_put(dev->driver->module);
David Schleefed9eccb2008-11-04 20:29:31 -08002315
2316 dev->use_count--;
2317
2318 mutex_unlock(&dev->mutex);
2319
David Schleefed9eccb2008-11-04 20:29:31 -08002320 return 0;
2321}
2322
Ian Abbott8cb8aad2012-06-19 10:17:43 +01002323static const struct file_operations comedi_fops = {
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302324 .owner = THIS_MODULE,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302325 .unlocked_ioctl = comedi_unlocked_ioctl,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302326 .compat_ioctl = comedi_compat_ioctl,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302327 .open = comedi_open,
2328 .release = comedi_close,
2329 .read = comedi_read,
2330 .write = comedi_write,
2331 .mmap = comedi_mmap,
2332 .poll = comedi_poll,
2333 .fasync = comedi_fasync,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002334 .llseek = noop_llseek,
David Schleefed9eccb2008-11-04 20:29:31 -08002335};
2336
Bill Pemberton71b5f4f2009-03-16 22:05:08 -04002337void comedi_error(const struct comedi_device *dev, const char *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002338{
Ian Abbott4f870fe2012-08-16 14:38:05 +01002339 dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
David Schleefed9eccb2008-11-04 20:29:31 -08002340}
H Hartley Sweeten5660e742013-04-12 10:11:54 -07002341EXPORT_SYMBOL_GPL(comedi_error);
David Schleefed9eccb2008-11-04 20:29:31 -08002342
Bill Pemberton34c43922009-03-16 22:05:14 -04002343void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002344{
Bill Pembertond1636792009-03-16 22:05:20 -04002345 struct comedi_async *async = s->async;
David Schleefed9eccb2008-11-04 20:29:31 -08002346 unsigned runflags = 0;
2347 unsigned runflags_mask = 0;
2348
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002349 /* DPRINTK("comedi_event 0x%x\n",mask); */
David Schleefed9eccb2008-11-04 20:29:31 -08002350
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002351 if (!comedi_is_subdevice_running(s))
David Schleefed9eccb2008-11-04 20:29:31 -08002352 return;
2353
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302354 if (s->
2355 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2356 COMEDI_CB_OVERFLOW)) {
David Schleefed9eccb2008-11-04 20:29:31 -08002357 runflags_mask |= SRF_RUNNING;
2358 }
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002359 /* remember if an error event has occurred, so an error
David Schleefed9eccb2008-11-04 20:29:31 -08002360 * can be returned the next time the user does a read() */
2361 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2362 runflags_mask |= SRF_ERROR;
2363 runflags |= SRF_ERROR;
2364 }
2365 if (runflags_mask) {
2366 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2367 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2368 }
2369
2370 if (async->cb_mask & s->async->events) {
2371 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
Greg Kroah-Hartmanfcea1152009-04-27 15:15:30 -07002372 wake_up_interruptible(&async->wait_head);
Andrea Gelmini6705b682010-02-26 10:14:55 +01002373 if (s->subdev_flags & SDF_CMD_READ)
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302374 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
Andrea Gelmini6705b682010-02-26 10:14:55 +01002375 if (s->subdev_flags & SDF_CMD_WRITE)
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302376 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
David Schleefed9eccb2008-11-04 20:29:31 -08002377 } else {
2378 if (async->cb_func)
2379 async->cb_func(s->async->events, async->cb_arg);
David Schleefed9eccb2008-11-04 20:29:31 -08002380 }
2381 }
2382 s->async->events = 0;
2383}
H Hartley Sweeten5660e742013-04-12 10:11:54 -07002384EXPORT_SYMBOL_GPL(comedi_event);
David Schleefed9eccb2008-11-04 20:29:31 -08002385
Ian Abbott07778392013-04-04 14:58:51 +01002386/* Note: the ->mutex is pre-locked on successful return */
Ian Abbott7638ffc2013-04-04 14:58:50 +01002387struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
David Schleefed9eccb2008-11-04 20:29:31 -08002388{
Ian Abbott7638ffc2013-04-04 14:58:50 +01002389 struct comedi_device *dev;
Bill Pemberton0bfbbe82009-03-16 22:05:36 -04002390 struct device *csdev;
David Schleefed9eccb2008-11-04 20:29:31 -08002391 unsigned i;
2392
Ian Abbott7638ffc2013-04-04 14:58:50 +01002393 dev = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002394 if (dev == NULL)
Ian Abbott7638ffc2013-04-04 14:58:50 +01002395 return ERR_PTR(-ENOMEM);
Ian Abbott7638ffc2013-04-04 14:58:50 +01002396 comedi_device_init(dev);
Ian Abbottdb2e3482013-04-04 14:59:00 +01002397 comedi_set_hw_dev(dev, hardware_device);
Ian Abbott07778392013-04-04 14:58:51 +01002398 mutex_lock(&dev->mutex);
Ian Abbott5b7dba12013-04-04 14:59:04 +01002399 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbott38b97222013-04-04 14:58:52 +01002400 for (i = hardware_device ? comedi_num_legacy_minors : 0;
2401 i < COMEDI_NUM_BOARD_MINORS; ++i) {
Ian Abbott5b7dba12013-04-04 14:59:04 +01002402 if (comedi_board_minor_table[i] == NULL) {
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002403 comedi_board_minor_table[i] = dev;
David Schleefed9eccb2008-11-04 20:29:31 -08002404 break;
2405 }
2406 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002407 mutex_unlock(&comedi_board_minor_table_lock);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002408 if (i == COMEDI_NUM_BOARD_MINORS) {
Ian Abbott07778392013-04-04 14:58:51 +01002409 mutex_unlock(&dev->mutex);
Ian Abbott7638ffc2013-04-04 14:58:50 +01002410 comedi_device_cleanup(dev);
2411 kfree(dev);
Ian Abbott4f870fe2012-08-16 14:38:05 +01002412 pr_err("comedi: error: ran out of minor numbers for board device files.\n");
Ian Abbott7638ffc2013-04-04 14:58:50 +01002413 return ERR_PTR(-EBUSY);
David Schleefed9eccb2008-11-04 20:29:31 -08002414 }
Ian Abbott7638ffc2013-04-04 14:58:50 +01002415 dev->minor = i;
Pavel Roskin0435f932011-07-06 10:15:44 -04002416 csdev = device_create(comedi_class, hardware_device,
2417 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002418 if (!IS_ERR(csdev))
Ian Abbott7638ffc2013-04-04 14:58:50 +01002419 dev->class_dev = csdev;
H Hartley Sweetena5011a22012-05-09 09:20:08 -07002420
Ian Abbott07778392013-04-04 14:58:51 +01002421 /* Note: dev->mutex needs to be unlocked by the caller. */
Ian Abbott7638ffc2013-04-04 14:58:50 +01002422 return dev;
David Schleefed9eccb2008-11-04 20:29:31 -08002423}
2424
Ian Abbott70f30c32013-04-04 14:58:49 +01002425static void comedi_free_board_minor(unsigned minor)
Ian Abbott24fb1342013-04-04 14:58:46 +01002426{
2427 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002428 comedi_free_board_dev(comedi_clear_board_minor(minor));
Ian Abbott24fb1342013-04-04 14:58:46 +01002429}
2430
Ian Abbott3346b792013-04-04 14:58:47 +01002431void comedi_release_hardware_device(struct device *hardware_device)
Ian Abbottc43435d2012-03-30 17:14:58 +01002432{
2433 int minor;
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002434 struct comedi_device *dev;
Ian Abbottc43435d2012-03-30 17:14:58 +01002435
Ian Abbott38b97222013-04-04 14:58:52 +01002436 for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
2437 minor++) {
Ian Abbott5b7dba12013-04-04 14:59:04 +01002438 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002439 dev = comedi_board_minor_table[minor];
2440 if (dev && dev->hw_dev == hardware_device) {
Ian Abbott5b7dba12013-04-04 14:59:04 +01002441 comedi_board_minor_table[minor] = NULL;
2442 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002443 comedi_free_board_dev(dev);
Ian Abbott3346b792013-04-04 14:58:47 +01002444 break;
Ian Abbottc43435d2012-03-30 17:14:58 +01002445 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002446 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottc43435d2012-03-30 17:14:58 +01002447 }
Ian Abbottc43435d2012-03-30 17:14:58 +01002448}
2449
Ian Abbottf65cc542013-02-01 10:20:30 +00002450int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002451{
Ian Abbottf65cc542013-02-01 10:20:30 +00002452 struct comedi_device *dev = s->device;
Bill Pemberton0bfbbe82009-03-16 22:05:36 -04002453 struct device *csdev;
David Schleefed9eccb2008-11-04 20:29:31 -08002454 unsigned i;
2455
Ian Abbott5b7dba12013-04-04 14:59:04 +01002456 mutex_lock(&comedi_subdevice_minor_table_lock);
2457 for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
2458 if (comedi_subdevice_minor_table[i] == NULL) {
Ian Abbottbd5b4172013-04-04 14:59:15 +01002459 comedi_subdevice_minor_table[i] = s;
David Schleefed9eccb2008-11-04 20:29:31 -08002460 break;
2461 }
2462 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002463 mutex_unlock(&comedi_subdevice_minor_table_lock);
2464 if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
Ian Abbottb12da2e2013-02-07 16:03:01 +00002465 pr_err("comedi: error: ran out of minor numbers for subdevice files.\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002466 return -EBUSY;
2467 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002468 i += COMEDI_NUM_BOARD_MINORS;
David Schleefed9eccb2008-11-04 20:29:31 -08002469 s->minor = i;
Pavel Roskin0435f932011-07-06 10:15:44 -04002470 csdev = device_create(comedi_class, dev->class_dev,
2471 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
H Hartley Sweeten90a35c12012-12-19 17:27:02 -07002472 dev->minor, s->index);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002473 if (!IS_ERR(csdev))
David Schleefed9eccb2008-11-04 20:29:31 -08002474 s->class_dev = csdev;
H Hartley Sweetena5011a22012-05-09 09:20:08 -07002475
Ian Abbottda718542013-02-07 16:03:00 +00002476 return 0;
David Schleefed9eccb2008-11-04 20:29:31 -08002477}
2478
Bill Pemberton34c43922009-03-16 22:05:14 -04002479void comedi_free_subdevice_minor(struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002480{
Ian Abbott0fcc9d42013-04-04 14:59:13 +01002481 unsigned int i;
David Schleefed9eccb2008-11-04 20:29:31 -08002482
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002483 if (s == NULL)
2484 return;
2485 if (s->minor < 0)
2486 return;
David Schleefed9eccb2008-11-04 20:29:31 -08002487
2488 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
Ian Abbott8907cf62013-04-04 14:59:03 +01002489 BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
David Schleefed9eccb2008-11-04 20:29:31 -08002490
Ian Abbott0fcc9d42013-04-04 14:59:13 +01002491 i = s->minor - COMEDI_NUM_BOARD_MINORS;
2492 mutex_lock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +01002493 if (s == comedi_subdevice_minor_table[i])
2494 comedi_subdevice_minor_table[i] = NULL;
Ian Abbott0fcc9d42013-04-04 14:59:13 +01002495 mutex_unlock(&comedi_subdevice_minor_table_lock);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002496 if (s->class_dev) {
David Schleefed9eccb2008-11-04 20:29:31 -08002497 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2498 s->class_dev = NULL;
2499 }
David Schleefed9eccb2008-11-04 20:29:31 -08002500}
H Hartley Sweetena5787822012-12-19 15:40:59 -07002501
Ian Abbott682b9112013-01-28 17:07:39 +00002502static void comedi_cleanup_board_minors(void)
H Hartley Sweeten76cca892012-12-19 15:41:42 -07002503{
2504 unsigned i;
2505
Ian Abbott682b9112013-01-28 17:07:39 +00002506 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
H Hartley Sweeten76cca892012-12-19 15:41:42 -07002507 comedi_free_board_minor(i);
2508}
2509
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002510static int __init comedi_init(void)
2511{
2512 int i;
2513 int retval;
2514
2515 pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
2516
2517 if (comedi_num_legacy_minors < 0 ||
2518 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
2519 pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n",
2520 COMEDI_NUM_BOARD_MINORS);
2521 return -EINVAL;
2522 }
2523
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002524 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2525 COMEDI_NUM_MINORS, "comedi");
2526 if (retval)
2527 return -EIO;
2528 cdev_init(&comedi_cdev, &comedi_fops);
2529 comedi_cdev.owner = THIS_MODULE;
2530 kobject_set_name(&comedi_cdev.kobj, "comedi");
2531 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2532 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2533 COMEDI_NUM_MINORS);
2534 return -EIO;
2535 }
2536 comedi_class = class_create(THIS_MODULE, "comedi");
2537 if (IS_ERR(comedi_class)) {
2538 pr_err("comedi: failed to create class\n");
2539 cdev_del(&comedi_cdev);
2540 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2541 COMEDI_NUM_MINORS);
2542 return PTR_ERR(comedi_class);
2543 }
2544
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -07002545 comedi_class->dev_groups = comedi_dev_groups;
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002546
2547 /* XXX requires /proc interface */
2548 comedi_proc_init();
2549
2550 /* create devices files for legacy/manual use */
2551 for (i = 0; i < comedi_num_legacy_minors; i++) {
Ian Abbott7638ffc2013-04-04 14:58:50 +01002552 struct comedi_device *dev;
2553 dev = comedi_alloc_board_minor(NULL);
2554 if (IS_ERR(dev)) {
Ian Abbott682b9112013-01-28 17:07:39 +00002555 comedi_cleanup_board_minors();
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002556 cdev_del(&comedi_cdev);
2557 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2558 COMEDI_NUM_MINORS);
Ian Abbott7638ffc2013-04-04 14:58:50 +01002559 return PTR_ERR(dev);
Ian Abbott07778392013-04-04 14:58:51 +01002560 } else {
2561 /* comedi_alloc_board_minor() locked the mutex */
2562 mutex_unlock(&dev->mutex);
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002563 }
2564 }
2565
2566 return 0;
2567}
2568module_init(comedi_init);
2569
2570static void __exit comedi_cleanup(void)
2571{
2572 int i;
2573
Ian Abbott682b9112013-01-28 17:07:39 +00002574 comedi_cleanup_board_minors();
Ian Abbott5b7dba12013-04-04 14:59:04 +01002575 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
2576 BUG_ON(comedi_board_minor_table[i]);
2577 for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
2578 BUG_ON(comedi_subdevice_minor_table[i]);
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002579
2580 class_destroy(comedi_class);
2581 cdev_del(&comedi_cdev);
2582 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2583
2584 comedi_proc_cleanup();
2585}
2586module_exit(comedi_cleanup);
2587
H Hartley Sweetena5787822012-12-19 15:40:59 -07002588MODULE_AUTHOR("http://www.comedi.org");
2589MODULE_DESCRIPTION("Comedi core module");
2590MODULE_LICENSE("GPL");