blob: 9d60a39ac9618fa03a853fda635bd82af4b63fe7 [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
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -070019#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -070050static int comedi_num_legacy_minors;
Ian Abbott4d7df822012-04-13 14:12:53 +010051module_param(comedi_num_legacy_minors, int, S_IRUGO);
52MODULE_PARM_DESC(comedi_num_legacy_minors,
53 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
54 );
55
Ian Abbott234bb3c2012-04-13 14:12:54 +010056unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
Ian Abbott4d7df822012-04-13 14:12:53 +010057module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
58MODULE_PARM_DESC(comedi_default_buf_size_kb,
59 "default asynchronous buffer size in KiB (default "
Ian Abbott234bb3c2012-04-13 14:12:54 +010060 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
Ian Abbott4d7df822012-04-13 14:12:53 +010061
Ian Abbott234bb3c2012-04-13 14:12:54 +010062unsigned int comedi_default_buf_maxsize_kb
63 = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
Ian Abbott4d7df822012-04-13 14:12:53 +010064module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
65MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
66 "default maximum size of asynchronous buffer in KiB (default "
Ian Abbott234bb3c2012-04-13 14:12:54 +010067 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
Bernd Porr1dd33ab2008-12-08 23:30:13 +000068
Ian Abbott5b7dba12013-04-04 14:59:04 +010069static DEFINE_MUTEX(comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +010070static struct comedi_device
Ian Abbott5b7dba12013-04-04 14:59:04 +010071*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
72
73static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
74/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
Ian Abbottbd5b4172013-04-04 14:59:15 +010075static struct comedi_subdevice
Ian Abbott5b7dba12013-04-04 14:59:04 +010076*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
David Schleefed9eccb2008-11-04 20:29:31 -080077
Ian Abbottd9740a02013-04-04 14:58:55 +010078static struct class *comedi_class;
79static struct cdev comedi_cdev;
80
81static void comedi_device_init(struct comedi_device *dev)
82{
Ian Abbott5b13ed92013-11-08 15:03:32 +000083 kref_init(&dev->refcount);
Ian Abbottd9740a02013-04-04 14:58:55 +010084 spin_lock_init(&dev->spinlock);
85 mutex_init(&dev->mutex);
Ian Abbott2f3fdcd2013-11-08 15:03:24 +000086 init_rwsem(&dev->attach_lock);
Ian Abbottd9740a02013-04-04 14:58:55 +010087 dev->minor = -1;
88}
89
Ian Abbott5b13ed92013-11-08 15:03:32 +000090static void comedi_dev_kref_release(struct kref *kref)
91{
92 struct comedi_device *dev =
93 container_of(kref, struct comedi_device, refcount);
94
95 mutex_destroy(&dev->mutex);
Ian Abbott8f988d82013-12-11 14:51:02 +000096 put_device(dev->class_dev);
Ian Abbott5b13ed92013-11-08 15:03:32 +000097 kfree(dev);
98}
99
100int comedi_dev_put(struct comedi_device *dev)
101{
102 if (dev)
103 return kref_put(&dev->refcount, comedi_dev_kref_release);
104 return 1;
105}
Ian Abbottb449c1c2013-11-08 15:03:33 +0000106EXPORT_SYMBOL_GPL(comedi_dev_put);
107
108static struct comedi_device *comedi_dev_get(struct comedi_device *dev)
109{
110 if (dev)
111 kref_get(&dev->refcount);
112 return dev;
113}
Ian Abbott5b13ed92013-11-08 15:03:32 +0000114
Ian Abbottd9740a02013-04-04 14:58:55 +0100115static void comedi_device_cleanup(struct comedi_device *dev)
116{
117 struct module *driver_module = NULL;
118
119 if (dev == NULL)
120 return;
121 mutex_lock(&dev->mutex);
122 if (dev->attached)
123 driver_module = dev->driver->module;
124 comedi_device_detach(dev);
Ian Abbott1363e4f2013-12-11 14:51:03 +0000125 if (driver_module && dev->use_count)
126 module_put(driver_module);
Ian Abbottd9740a02013-04-04 14:58:55 +0100127 mutex_unlock(&dev->mutex);
Ian Abbottd9740a02013-04-04 14:58:55 +0100128}
129
Ian Abbottdb210da2013-04-04 14:59:18 +0100130static bool comedi_clear_board_dev(struct comedi_device *dev)
131{
132 unsigned int i = dev->minor;
133 bool cleared = false;
134
135 mutex_lock(&comedi_board_minor_table_lock);
136 if (dev == comedi_board_minor_table[i]) {
137 comedi_board_minor_table[i] = NULL;
138 cleared = true;
139 }
140 mutex_unlock(&comedi_board_minor_table_lock);
141 return cleared;
142}
143
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100144static struct comedi_device *comedi_clear_board_minor(unsigned minor)
Ian Abbottd9740a02013-04-04 14:58:55 +0100145{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100146 struct comedi_device *dev;
Ian Abbottd9740a02013-04-04 14:58:55 +0100147
Ian Abbott5b7dba12013-04-04 14:59:04 +0100148 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100149 dev = comedi_board_minor_table[minor];
Ian Abbott5b7dba12013-04-04 14:59:04 +0100150 comedi_board_minor_table[minor] = NULL;
151 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100152 return dev;
Ian Abbottd9740a02013-04-04 14:58:55 +0100153}
154
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100155static void comedi_free_board_dev(struct comedi_device *dev)
Ian Abbottd9740a02013-04-04 14:58:55 +0100156{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100157 if (dev) {
Ian Abbott52ef9e72014-01-07 12:38:32 +0000158 comedi_device_cleanup(dev);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100159 if (dev->class_dev) {
160 device_destroy(comedi_class,
161 MKDEV(COMEDI_MAJOR, dev->minor));
Ian Abbottd9740a02013-04-04 14:58:55 +0100162 }
Ian Abbott5b13ed92013-11-08 15:03:32 +0000163 comedi_dev_put(dev);
Ian Abbottd9740a02013-04-04 14:58:55 +0100164 }
165}
Ian Abbott8ab4ed62013-04-04 14:58:54 +0100166
Ian Abbottbd5b4172013-04-04 14:59:15 +0100167static struct comedi_subdevice
Ian Abbott63ab0392013-11-08 15:03:42 +0000168*comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned minor)
Ian Abbott5b7dba12013-04-04 14:59:04 +0100169{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100170 struct comedi_subdevice *s;
Ian Abbott5b7dba12013-04-04 14:59:04 +0100171 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
172
173 BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
174 mutex_lock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +0100175 s = comedi_subdevice_minor_table[i];
Ian Abbott63ab0392013-11-08 15:03:42 +0000176 if (s && s->device != dev)
177 s = NULL;
Ian Abbott5b7dba12013-04-04 14:59:04 +0100178 mutex_unlock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +0100179 return s;
Ian Abbott5b7dba12013-04-04 14:59:04 +0100180}
181
Ian Abbottb449c1c2013-11-08 15:03:33 +0000182static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor)
183{
184 struct comedi_device *dev;
185
186 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
187 mutex_lock(&comedi_board_minor_table_lock);
188 dev = comedi_dev_get(comedi_board_minor_table[minor]);
189 mutex_unlock(&comedi_board_minor_table_lock);
190 return dev;
191}
192
193static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
194{
195 struct comedi_device *dev;
196 struct comedi_subdevice *s;
197 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
198
199 BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
200 mutex_lock(&comedi_subdevice_minor_table_lock);
201 s = comedi_subdevice_minor_table[i];
202 dev = comedi_dev_get(s ? s->device : NULL);
203 mutex_unlock(&comedi_subdevice_minor_table_lock);
204 return dev;
205}
206
207struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
208{
209 if (minor < COMEDI_NUM_BOARD_MINORS)
210 return comedi_dev_get_from_board_minor(minor);
Kinka Huangcb3aada2014-07-15 23:11:02 +0800211
212 return comedi_dev_get_from_subdevice_minor(minor);
Ian Abbottb449c1c2013-11-08 15:03:33 +0000213}
214EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor);
215
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700216static struct comedi_subdevice *
Ian Abbottda56fdc2013-04-04 14:59:10 +0100217comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700218{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100219 struct comedi_subdevice *s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100220
221 if (minor >= COMEDI_NUM_BOARD_MINORS) {
Ian Abbott63ab0392013-11-08 15:03:42 +0000222 s = comedi_subdevice_from_minor(dev, minor);
223 if (s == NULL || (s->subdev_flags & SDF_CMD_READ))
Ian Abbottbd5b4172013-04-04 14:59:15 +0100224 return s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100225 }
226 return dev->read_subdev;
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700227}
228
229static struct comedi_subdevice *
Ian Abbottda56fdc2013-04-04 14:59:10 +0100230comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700231{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100232 struct comedi_subdevice *s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100233
234 if (minor >= COMEDI_NUM_BOARD_MINORS) {
Ian Abbott63ab0392013-11-08 15:03:42 +0000235 s = comedi_subdevice_from_minor(dev, minor);
236 if (s == NULL || (s->subdev_flags & SDF_CMD_WRITE))
Ian Abbottbd5b4172013-04-04 14:59:15 +0100237 return s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100238 }
239 return dev->write_subdev;
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700240}
241
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400242static int resize_async_buffer(struct comedi_device *dev,
Ian Abbott482f0a22014-05-02 13:50:14 +0100243 struct comedi_subdevice *s, unsigned new_size)
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700244{
Ian Abbott482f0a22014-05-02 13:50:14 +0100245 struct comedi_async *async = s->async;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700246 int retval;
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400247
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700248 if (new_size > async->max_bufsize)
249 return -EPERM;
250
251 if (s->busy) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700252 dev_dbg(dev->class_dev,
253 "subdevice is busy, cannot resize buffer\n");
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700254 return -EBUSY;
255 }
Ian Abbottd4526ab2014-05-06 13:12:11 +0100256 if (comedi_buf_is_mmapped(s)) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700257 dev_dbg(dev->class_dev,
258 "subdevice is mmapped, cannot resize buffer\n");
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700259 return -EBUSY;
260 }
261
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700262 /* make sure buffer is an integral number of pages
263 * (we round up) */
264 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
265
266 retval = comedi_buf_alloc(dev, s, new_size);
267 if (retval < 0)
268 return retval;
269
270 if (s->buf_change) {
H Hartley Sweetend546b892014-07-21 11:48:32 -0700271 retval = s->buf_change(dev, s);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700272 if (retval < 0)
273 return retval;
274 }
275
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700276 dev_dbg(dev->class_dev, "subd %d buffer resized to %i bytes\n",
277 s->index, async->prealloc_bufsz);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700278 return 0;
279}
280
281/* sysfs attribute files */
282
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700283static ssize_t max_read_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700284 struct device_attribute *attr, char *buf)
285{
Ian Abbottc88db462013-04-04 14:59:09 +0100286 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100287 struct comedi_device *dev;
288 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700289 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700290
Ian Abbottbe535c92013-11-08 15:03:37 +0000291 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100292 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100293 return -ENODEV;
294
Ian Abbott7f4656c2013-04-04 14:59:08 +0100295 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100296 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700297 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
298 size = s->async->max_bufsize / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100299 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700300
Ian Abbottbe535c92013-11-08 15:03:37 +0000301 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600302 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700303}
304
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700305static ssize_t max_read_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700306 struct device_attribute *attr,
307 const char *buf, size_t count)
308{
Ian Abbottc88db462013-04-04 14:59:09 +0100309 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100310 struct comedi_device *dev;
311 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700312 unsigned int size;
313 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700314
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700315 err = kstrtouint(buf, 10, &size);
316 if (err)
317 return err;
318 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700319 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700320 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700321
Ian Abbottbe535c92013-11-08 15:03:37 +0000322 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100323 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100324 return -ENODEV;
325
Ian Abbott7f4656c2013-04-04 14:59:08 +0100326 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100327 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700328 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
329 s->async->max_bufsize = size;
330 else
331 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100332 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700333
Ian Abbottbe535c92013-11-08 15:03:37 +0000334 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700335 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700336}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700337static DEVICE_ATTR_RW(max_read_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700338
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700339static ssize_t read_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700340 struct device_attribute *attr, char *buf)
341{
Ian Abbottc88db462013-04-04 14:59:09 +0100342 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100343 struct comedi_device *dev;
344 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700345 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700346
Ian Abbottbe535c92013-11-08 15:03:37 +0000347 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100348 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100349 return -ENODEV;
350
Ian Abbott7f4656c2013-04-04 14:59:08 +0100351 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100352 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700353 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
354 size = s->async->prealloc_bufsz / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100355 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700356
Ian Abbottbe535c92013-11-08 15:03:37 +0000357 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600358 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700359}
360
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700361static ssize_t read_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700362 struct device_attribute *attr,
363 const char *buf, size_t count)
364{
Ian Abbottc88db462013-04-04 14:59:09 +0100365 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100366 struct comedi_device *dev;
367 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700368 unsigned int size;
369 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700370
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700371 err = kstrtouint(buf, 10, &size);
372 if (err)
373 return err;
374 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700375 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700376 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700377
Ian Abbottbe535c92013-11-08 15:03:37 +0000378 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100379 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100380 return -ENODEV;
381
Ian Abbott7f4656c2013-04-04 14:59:08 +0100382 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100383 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700384 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
Ian Abbott482f0a22014-05-02 13:50:14 +0100385 err = resize_async_buffer(dev, s, size);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700386 else
387 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100388 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700389
Ian Abbottbe535c92013-11-08 15:03:37 +0000390 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700391 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700392}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700393static DEVICE_ATTR_RW(read_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700394
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700395static ssize_t max_write_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700396 struct device_attribute *attr,
397 char *buf)
398{
Ian Abbottc88db462013-04-04 14:59:09 +0100399 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100400 struct comedi_device *dev;
401 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700402 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700403
Ian Abbottbe535c92013-11-08 15:03:37 +0000404 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100405 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100406 return -ENODEV;
407
Ian Abbott7f4656c2013-04-04 14:59:08 +0100408 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100409 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700410 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
411 size = s->async->max_bufsize / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100412 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700413
Ian Abbottbe535c92013-11-08 15:03:37 +0000414 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600415 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700416}
417
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700418static ssize_t max_write_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700419 struct device_attribute *attr,
420 const char *buf, size_t count)
421{
Ian Abbottc88db462013-04-04 14:59:09 +0100422 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100423 struct comedi_device *dev;
424 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700425 unsigned int size;
426 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700427
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700428 err = kstrtouint(buf, 10, &size);
429 if (err)
430 return err;
431 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700432 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700433 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700434
Ian Abbottbe535c92013-11-08 15:03:37 +0000435 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100436 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 s->async->max_bufsize = size;
443 else
444 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100445 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700446
Ian Abbottbe535c92013-11-08 15:03:37 +0000447 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700448 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700449}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700450static DEVICE_ATTR_RW(max_write_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700451
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700452static ssize_t write_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700453 struct device_attribute *attr, char *buf)
454{
Ian Abbottc88db462013-04-04 14:59:09 +0100455 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100456 struct comedi_device *dev;
457 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700458 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700459
Ian Abbottbe535c92013-11-08 15:03:37 +0000460 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100461 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100462 return -ENODEV;
463
Ian Abbott7f4656c2013-04-04 14:59:08 +0100464 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100465 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700466 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
467 size = s->async->prealloc_bufsz / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100468 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700469
Ian Abbottbe535c92013-11-08 15:03:37 +0000470 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600471 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700472}
473
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700474static ssize_t write_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700475 struct device_attribute *attr,
476 const char *buf, size_t count)
477{
Ian Abbottc88db462013-04-04 14:59:09 +0100478 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100479 struct comedi_device *dev;
480 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700481 unsigned int size;
482 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700483
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700484 err = kstrtouint(buf, 10, &size);
485 if (err)
486 return err;
487 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700488 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700489 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700490
Ian Abbottbe535c92013-11-08 15:03:37 +0000491 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100492 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100493 return -ENODEV;
494
Ian Abbott7f4656c2013-04-04 14:59:08 +0100495 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100496 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700497 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
Ian Abbott482f0a22014-05-02 13:50:14 +0100498 err = resize_async_buffer(dev, s, size);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700499 else
500 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100501 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700502
Ian Abbottbe535c92013-11-08 15:03:37 +0000503 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700504 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700505}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700506static DEVICE_ATTR_RW(write_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700507
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700508static struct attribute *comedi_dev_attrs[] = {
509 &dev_attr_max_read_buffer_kb.attr,
510 &dev_attr_read_buffer_kb.attr,
511 &dev_attr_max_write_buffer_kb.attr,
512 &dev_attr_write_buffer_kb.attr,
513 NULL,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700514};
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700515ATTRIBUTE_GROUPS(comedi_dev);
David Schleefed9eccb2008-11-04 20:29:31 -0800516
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700517static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
518 unsigned mask, unsigned bits)
519{
520 unsigned long flags;
521
522 spin_lock_irqsave(&s->spin_lock, flags);
523 s->runflags &= ~mask;
524 s->runflags |= (bits & mask);
525 spin_unlock_irqrestore(&s->spin_lock, flags);
526}
527
H Hartley Sweetenade17642012-12-19 15:43:40 -0700528static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
H Hartley Sweeten74120712012-12-19 15:42:26 -0700529{
530 unsigned long flags;
531 unsigned runflags;
532
533 spin_lock_irqsave(&s->spin_lock, flags);
534 runflags = s->runflags;
535 spin_unlock_irqrestore(&s->spin_lock, flags);
536 return runflags;
537}
H Hartley Sweeten74120712012-12-19 15:42:26 -0700538
H Hartley Sweetene0dac312012-12-19 15:42:47 -0700539bool comedi_is_subdevice_running(struct comedi_subdevice *s)
540{
541 unsigned runflags = comedi_get_subdevice_runflags(s);
542
543 return (runflags & SRF_RUNNING) ? true : false;
544}
545EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
546
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -0700547static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
548{
549 unsigned runflags = comedi_get_subdevice_runflags(s);
550
551 return (runflags & SRF_ERROR) ? true : false;
552}
553
H Hartley Sweeten9682e282012-12-19 15:44:24 -0700554static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
555{
556 unsigned runflags = comedi_get_subdevice_runflags(s);
557
558 return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
559}
560
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700561/**
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700562 * comedi_alloc_spriv() - Allocate memory for the subdevice private data.
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700563 * @s: comedi_subdevice struct
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700564 * @size: size of the memory to allocate
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700565 *
566 * This also sets the subdevice runflags to allow the core to automatically
567 * free the private data during the detach.
568 */
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700569void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700570{
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700571 s->private = kzalloc(size, GFP_KERNEL);
572 if (s->private)
Ian Abbott67aa4ac2013-10-07 15:51:58 +0100573 s->runflags |= SRF_FREE_SPRIV;
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700574 return s->private;
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700575}
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700576EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700577
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700578/*
579 This function restores a subdevice to an idle state.
580 */
581static void do_become_nonbusy(struct comedi_device *dev,
582 struct comedi_subdevice *s)
583{
584 struct comedi_async *async = s->async;
585
586 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
587 if (async) {
Ian Abbottfcc18a92014-05-06 13:12:10 +0100588 comedi_buf_reset(s);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700589 async->inttrig = NULL;
590 kfree(async->cmd.chanlist);
591 async->cmd.chanlist = NULL;
Ian Abbott8da8c862013-11-08 15:03:27 +0000592 s->busy = NULL;
593 wake_up_interruptible_all(&s->async->wait_head);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700594 } else {
595 dev_err(dev->class_dev,
596 "BUG: (?) do_become_nonbusy called with async=NULL\n");
Ian Abbott8da8c862013-11-08 15:03:27 +0000597 s->busy = NULL;
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700598 }
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700599}
600
601static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
602{
603 int ret = 0;
604
H Hartley Sweetenf0124632012-12-19 15:43:18 -0700605 if (comedi_is_subdevice_running(s) && s->cancel)
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700606 ret = s->cancel(dev, s);
607
608 do_become_nonbusy(dev, s);
609
610 return ret;
611}
612
Ian Abbottd19db512013-11-08 15:03:28 +0000613void comedi_device_cancel_all(struct comedi_device *dev)
614{
615 struct comedi_subdevice *s;
616 int i;
617
618 if (!dev->attached)
619 return;
620
621 for (i = 0; i < dev->n_subdevices; i++) {
622 s = &dev->subdevices[i];
623 if (s->async)
624 do_cancel(dev, s);
625 }
626}
627
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700628static int is_device_busy(struct comedi_device *dev)
629{
630 struct comedi_subdevice *s;
631 int i;
632
633 if (!dev->attached)
634 return 0;
635
636 for (i = 0; i < dev->n_subdevices; i++) {
637 s = &dev->subdevices[i];
638 if (s->busy)
639 return 1;
Ian Abbottd4526ab2014-05-06 13:12:11 +0100640 if (s->async && comedi_buf_is_mmapped(s))
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700641 return 1;
642 }
643
644 return 0;
645}
646
David Schleefed9eccb2008-11-04 20:29:31 -0800647/*
648 COMEDI_DEVCONFIG
649 device config ioctl
650
651 arg:
652 pointer to devconfig structure
653
654 reads:
655 devconfig structure at arg
656
657 writes:
658 none
659*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530660static int do_devconfig_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700661 struct comedi_devconfig __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800662{
Bill Pemberton0707bb02009-03-16 22:06:20 -0400663 struct comedi_devconfig it;
David Schleefed9eccb2008-11-04 20:29:31 -0800664
665 if (!capable(CAP_SYS_ADMIN))
666 return -EPERM;
667
668 if (arg == NULL) {
669 if (is_device_busy(dev))
670 return -EBUSY;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800671 if (dev->attached) {
David Schleefed9eccb2008-11-04 20:29:31 -0800672 struct module *driver_module = dev->driver->module;
Raghavendra Ganiga4bac39f2014-05-01 13:53:12 +0530673
David Schleefed9eccb2008-11-04 20:29:31 -0800674 comedi_device_detach(dev);
675 module_put(driver_module);
676 }
677 return 0;
678 }
679
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700680 if (copy_from_user(&it, arg, sizeof(it)))
David Schleefed9eccb2008-11-04 20:29:31 -0800681 return -EFAULT;
682
683 it.board_name[COMEDI_NAMELEN - 1] = 0;
684
H Hartley Sweetend1843132013-01-09 09:46:10 -0700685 if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
686 dev_warn(dev->class_dev,
687 "comedi_config --init_data is deprecated\n");
688 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -0800689 }
690
Ian Abbott8ab4ed62013-04-04 14:58:54 +0100691 if (dev->minor >= comedi_num_legacy_minors)
692 /* don't re-use dynamically allocated comedi devices */
693 return -EBUSY;
694
Ian Abbottb2a644b2013-04-04 14:58:56 +0100695 /* This increments the driver module count on success. */
696 return comedi_device_attach(dev, &it);
David Schleefed9eccb2008-11-04 20:29:31 -0800697}
698
699/*
700 COMEDI_BUFCONFIG
701 buffer configuration ioctl
702
703 arg:
704 pointer to bufconfig structure
705
706 reads:
707 bufconfig at arg
708
709 writes:
710 modified bufconfig at arg
711
712*/
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700713static int do_bufconfig_ioctl(struct comedi_device *dev,
714 struct comedi_bufconfig __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800715{
Bill Pembertonbe6aba42009-03-16 22:06:37 -0400716 struct comedi_bufconfig bc;
Bill Pembertond1636792009-03-16 22:05:20 -0400717 struct comedi_async *async;
Bill Pemberton34c43922009-03-16 22:05:14 -0400718 struct comedi_subdevice *s;
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400719 int retval = 0;
David Schleefed9eccb2008-11-04 20:29:31 -0800720
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700721 if (copy_from_user(&bc, arg, sizeof(bc)))
David Schleefed9eccb2008-11-04 20:29:31 -0800722 return -EFAULT;
723
Güngör Erseymen11f80dd2013-06-07 21:29:49 +0300724 if (bc.subdevice >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -0800725 return -EINVAL;
726
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700727 s = &dev->subdevices[bc.subdevice];
David Schleefed9eccb2008-11-04 20:29:31 -0800728 async = s->async;
729
730 if (!async) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700731 dev_dbg(dev->class_dev,
732 "subdevice does not have async capability\n");
David Schleefed9eccb2008-11-04 20:29:31 -0800733 bc.size = 0;
734 bc.maximum_size = 0;
735 goto copyback;
736 }
737
738 if (bc.maximum_size) {
739 if (!capable(CAP_SYS_ADMIN))
740 return -EPERM;
741
742 async->max_bufsize = bc.maximum_size;
743 }
744
745 if (bc.size) {
Ian Abbott482f0a22014-05-02 13:50:14 +0100746 retval = resize_async_buffer(dev, s, bc.size);
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400747 if (retval < 0)
748 return retval;
David Schleefed9eccb2008-11-04 20:29:31 -0800749 }
750
751 bc.size = async->prealloc_bufsz;
752 bc.maximum_size = async->max_bufsize;
753
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800754copyback:
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700755 if (copy_to_user(arg, &bc, sizeof(bc)))
David Schleefed9eccb2008-11-04 20:29:31 -0800756 return -EFAULT;
757
758 return 0;
759}
760
761/*
762 COMEDI_DEVINFO
763 device info ioctl
764
765 arg:
766 pointer to devinfo structure
767
768 reads:
769 none
770
771 writes:
772 devinfo structure
773
774*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530775static int do_devinfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700776 struct comedi_devinfo __user *arg,
777 struct file *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800778{
Al Viro6131ffa2013-02-27 16:59:05 -0500779 const unsigned minor = iminor(file_inode(file));
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700780 struct comedi_subdevice *s;
781 struct comedi_devinfo devinfo;
David Schleefed9eccb2008-11-04 20:29:31 -0800782
783 memset(&devinfo, 0, sizeof(devinfo));
784
785 /* fill devinfo structure */
786 devinfo.version_code = COMEDI_VERSION_CODE;
787 devinfo.n_subdevs = dev->n_subdevices;
Vasiliy Kulikov819cbb12011-06-26 12:56:22 +0400788 strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
789 strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
David Schleefed9eccb2008-11-04 20:29:31 -0800790
Ian Abbottda56fdc2013-04-04 14:59:10 +0100791 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700792 if (s)
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700793 devinfo.read_subdevice = s->index;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800794 else
David Schleefed9eccb2008-11-04 20:29:31 -0800795 devinfo.read_subdevice = -1;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800796
Ian Abbottda56fdc2013-04-04 14:59:10 +0100797 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700798 if (s)
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700799 devinfo.write_subdevice = s->index;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800800 else
David Schleefed9eccb2008-11-04 20:29:31 -0800801 devinfo.write_subdevice = -1;
David Schleefed9eccb2008-11-04 20:29:31 -0800802
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700803 if (copy_to_user(arg, &devinfo, sizeof(devinfo)))
David Schleefed9eccb2008-11-04 20:29:31 -0800804 return -EFAULT;
805
806 return 0;
807}
808
809/*
810 COMEDI_SUBDINFO
811 subdevice info ioctl
812
813 arg:
814 pointer to array of subdevice info structures
815
816 reads:
817 none
818
819 writes:
820 array of subdevice info structures at arg
821
822*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530823static int do_subdinfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700824 struct comedi_subdinfo __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800825{
826 int ret, i;
Bill Pembertonbd52efb2009-03-16 22:06:09 -0400827 struct comedi_subdinfo *tmp, *us;
Bill Pemberton34c43922009-03-16 22:05:14 -0400828 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -0800829
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700830 tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL);
David Schleefed9eccb2008-11-04 20:29:31 -0800831 if (!tmp)
832 return -ENOMEM;
833
834 /* fill subdinfo structs */
835 for (i = 0; i < dev->n_subdevices; i++) {
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700836 s = &dev->subdevices[i];
David Schleefed9eccb2008-11-04 20:29:31 -0800837 us = tmp + i;
838
839 us->type = s->type;
840 us->n_chan = s->n_chan;
841 us->subd_flags = s->subdev_flags;
H Hartley Sweetenf0124632012-12-19 15:43:18 -0700842 if (comedi_is_subdevice_running(s))
David Schleefed9eccb2008-11-04 20:29:31 -0800843 us->subd_flags |= SDF_RUNNING;
844#define TIMER_nanosec 5 /* backwards compatibility */
845 us->timer_type = TIMER_nanosec;
846 us->len_chanlist = s->len_chanlist;
847 us->maxdata = s->maxdata;
848 if (s->range_table) {
849 us->range_type =
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800850 (i << 24) | (0 << 16) | (s->range_table->length);
David Schleefed9eccb2008-11-04 20:29:31 -0800851 } else {
852 us->range_type = 0; /* XXX */
853 }
David Schleefed9eccb2008-11-04 20:29:31 -0800854
855 if (s->busy)
856 us->subd_flags |= SDF_BUSY;
857 if (s->busy == file)
858 us->subd_flags |= SDF_BUSY_OWNER;
859 if (s->lock)
860 us->subd_flags |= SDF_LOCKED;
861 if (s->lock == file)
862 us->subd_flags |= SDF_LOCK_OWNER;
863 if (!s->maxdata && s->maxdata_list)
864 us->subd_flags |= SDF_MAXDATA;
David Schleefed9eccb2008-11-04 20:29:31 -0800865 if (s->range_table_list)
866 us->subd_flags |= SDF_RANGETYPE;
867 if (s->do_cmd)
868 us->subd_flags |= SDF_CMD;
869
870 if (s->insn_bits != &insn_inval)
871 us->insn_bits_support = COMEDI_SUPPORTED;
872 else
873 us->insn_bits_support = COMEDI_UNSUPPORTED;
David Schleefed9eccb2008-11-04 20:29:31 -0800874 }
875
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700876 ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp));
David Schleefed9eccb2008-11-04 20:29:31 -0800877
878 kfree(tmp);
879
880 return ret ? -EFAULT : 0;
881}
882
883/*
884 COMEDI_CHANINFO
885 subdevice info ioctl
886
887 arg:
888 pointer to chaninfo structure
889
890 reads:
891 chaninfo structure at arg
892
893 writes:
894 arrays at elements of chaninfo structure
895
896*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530897static int do_chaninfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700898 struct comedi_chaninfo __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800899{
Bill Pemberton34c43922009-03-16 22:05:14 -0400900 struct comedi_subdevice *s;
Bill Pembertona18b4162009-03-16 22:06:04 -0400901 struct comedi_chaninfo it;
David Schleefed9eccb2008-11-04 20:29:31 -0800902
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700903 if (copy_from_user(&it, arg, sizeof(it)))
David Schleefed9eccb2008-11-04 20:29:31 -0800904 return -EFAULT;
905
906 if (it.subdev >= dev->n_subdevices)
907 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700908 s = &dev->subdevices[it.subdev];
David Schleefed9eccb2008-11-04 20:29:31 -0800909
910 if (it.maxdata_list) {
911 if (s->maxdata || !s->maxdata_list)
912 return -EINVAL;
913 if (copy_to_user(it.maxdata_list, s->maxdata_list,
Bill Pemberton790c5542009-03-16 22:05:02 -0400914 s->n_chan * sizeof(unsigned int)))
David Schleefed9eccb2008-11-04 20:29:31 -0800915 return -EFAULT;
916 }
917
Ian Abbott64d9b1d2013-10-07 16:50:05 +0100918 if (it.flaglist)
919 return -EINVAL; /* flaglist not supported */
David Schleefed9eccb2008-11-04 20:29:31 -0800920
921 if (it.rangelist) {
922 int i;
923
924 if (!s->range_table_list)
925 return -EINVAL;
926 for (i = 0; i < s->n_chan; i++) {
927 int x;
928
929 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800930 (s->range_table_list[i]->length);
Vasiliy Kulikov81604d42010-09-05 22:32:33 +0400931 if (put_user(x, it.rangelist + i))
932 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -0800933 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800934#if 0
935 if (copy_to_user(it.rangelist, s->range_type_list,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530936 s->n_chan * sizeof(unsigned int)))
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800937 return -EFAULT;
938#endif
David Schleefed9eccb2008-11-04 20:29:31 -0800939 }
940
941 return 0;
942}
943
944 /*
945 COMEDI_BUFINFO
946 buffer information ioctl
947
948 arg:
949 pointer to bufinfo structure
950
951 reads:
952 bufinfo at arg
953
954 writes:
955 modified bufinfo at arg
956
957 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700958static int do_bufinfo_ioctl(struct comedi_device *dev,
Ian Abbott53fa8272010-05-19 18:09:50 +0100959 struct comedi_bufinfo __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800960{
Bill Pemberton9aa53392009-03-16 22:06:42 -0400961 struct comedi_bufinfo bi;
Bill Pemberton34c43922009-03-16 22:05:14 -0400962 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -0400963 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -0800964
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700965 if (copy_from_user(&bi, arg, sizeof(bi)))
David Schleefed9eccb2008-11-04 20:29:31 -0800966 return -EFAULT;
967
Güngör Erseymen7b1a5e22013-06-07 21:29:50 +0300968 if (bi.subdevice >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -0800969 return -EINVAL;
970
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700971 s = &dev->subdevices[bi.subdevice];
Ian Abbott53fa8272010-05-19 18:09:50 +0100972
David Schleefed9eccb2008-11-04 20:29:31 -0800973 async = s->async;
974
975 if (!async) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700976 dev_dbg(dev->class_dev,
977 "subdevice does not have async capability\n");
David Schleefed9eccb2008-11-04 20:29:31 -0800978 bi.buf_write_ptr = 0;
979 bi.buf_read_ptr = 0;
980 bi.buf_write_count = 0;
981 bi.buf_read_count = 0;
Ian Abbott4772c012010-05-19 18:09:49 +0100982 bi.bytes_read = 0;
983 bi.bytes_written = 0;
David Schleefed9eccb2008-11-04 20:29:31 -0800984 goto copyback;
985 }
Ian Abbott53fa8272010-05-19 18:09:50 +0100986 if (!s->busy) {
987 bi.bytes_read = 0;
988 bi.bytes_written = 0;
989 goto copyback_position;
990 }
991 if (s->busy != file)
992 return -EACCES;
David Schleefed9eccb2008-11-04 20:29:31 -0800993
994 if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
Ian Abbottd13be552014-05-06 13:12:07 +0100995 bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read);
Ian Abbottf1df8662014-05-06 13:12:08 +0100996 comedi_buf_read_free(s, bi.bytes_read);
David Schleefed9eccb2008-11-04 20:29:31 -0800997
H Hartley Sweeten9682e282012-12-19 15:44:24 -0700998 if (comedi_is_subdevice_idle(s) &&
H Hartley Sweetenf4f3f7c2014-06-20 10:58:28 -0700999 comedi_buf_n_bytes_ready(s) == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001000 do_become_nonbusy(dev, s);
1001 }
1002 }
1003
1004 if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
1005 bi.bytes_written =
Ian Abbott24e894b2014-05-06 13:12:04 +01001006 comedi_buf_write_alloc(s, bi.bytes_written);
Ian Abbott940dd352014-05-06 13:12:05 +01001007 comedi_buf_write_free(s, bi.bytes_written);
David Schleefed9eccb2008-11-04 20:29:31 -08001008 }
1009
Ian Abbott53fa8272010-05-19 18:09:50 +01001010copyback_position:
David Schleefed9eccb2008-11-04 20:29:31 -08001011 bi.buf_write_count = async->buf_write_count;
1012 bi.buf_write_ptr = async->buf_write_ptr;
1013 bi.buf_read_count = async->buf_read_count;
1014 bi.buf_read_ptr = async->buf_read_ptr;
1015
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001016copyback:
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001017 if (copy_to_user(arg, &bi, sizeof(bi)))
David Schleefed9eccb2008-11-04 20:29:31 -08001018 return -EFAULT;
1019
1020 return 0;
1021}
1022
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301023static int check_insn_config_length(struct comedi_insn *insn,
1024 unsigned int *data)
David Schleefed9eccb2008-11-04 20:29:31 -08001025{
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001026 if (insn->n < 1)
1027 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001028
1029 switch (data[0]) {
1030 case INSN_CONFIG_DIO_OUTPUT:
1031 case INSN_CONFIG_DIO_INPUT:
1032 case INSN_CONFIG_DISARM:
1033 case INSN_CONFIG_RESET:
1034 if (insn->n == 1)
1035 return 0;
1036 break;
1037 case INSN_CONFIG_ARM:
1038 case INSN_CONFIG_DIO_QUERY:
1039 case INSN_CONFIG_BLOCK_SIZE:
1040 case INSN_CONFIG_FILTER:
1041 case INSN_CONFIG_SERIAL_CLOCK:
1042 case INSN_CONFIG_BIDIRECTIONAL_DATA:
1043 case INSN_CONFIG_ALT_SOURCE:
1044 case INSN_CONFIG_SET_COUNTER_MODE:
1045 case INSN_CONFIG_8254_READ_STATUS:
1046 case INSN_CONFIG_SET_ROUTING:
1047 case INSN_CONFIG_GET_ROUTING:
1048 case INSN_CONFIG_GET_PWM_STATUS:
1049 case INSN_CONFIG_PWM_SET_PERIOD:
1050 case INSN_CONFIG_PWM_GET_PERIOD:
1051 if (insn->n == 2)
1052 return 0;
1053 break;
1054 case INSN_CONFIG_SET_GATE_SRC:
1055 case INSN_CONFIG_GET_GATE_SRC:
1056 case INSN_CONFIG_SET_CLOCK_SRC:
1057 case INSN_CONFIG_GET_CLOCK_SRC:
1058 case INSN_CONFIG_SET_OTHER_SRC:
1059 case INSN_CONFIG_GET_COUNTER_STATUS:
1060 case INSN_CONFIG_PWM_SET_H_BRIDGE:
1061 case INSN_CONFIG_PWM_GET_H_BRIDGE:
1062 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
1063 if (insn->n == 3)
1064 return 0;
1065 break;
1066 case INSN_CONFIG_PWM_OUTPUT:
1067 case INSN_CONFIG_ANALOG_TRIG:
1068 if (insn->n == 5)
1069 return 0;
1070 break;
Ian Abbottb0a2b6d2012-11-14 11:22:57 +00001071 case INSN_CONFIG_DIGITAL_TRIG:
1072 if (insn->n == 6)
1073 return 0;
1074 break;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301075 /* by default we allow the insn since we don't have checks for
1076 * all possible cases yet */
David Schleefed9eccb2008-11-04 20:29:31 -08001077 default:
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07001078 pr_warn("No check for data length of config insn id %i is implemented\n",
Ian Abbott4f870fe2012-08-16 14:38:05 +01001079 data[0]);
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07001080 pr_warn("Add a check to %s in %s\n", __func__, __FILE__);
1081 pr_warn("Assuming n=%i is correct\n", insn->n);
David Schleefed9eccb2008-11-04 20:29:31 -08001082 return 0;
David Schleefed9eccb2008-11-04 20:29:31 -08001083 }
1084 return -EINVAL;
1085}
1086
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301087static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
1088 unsigned int *data, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001089{
Bill Pemberton34c43922009-03-16 22:05:14 -04001090 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001091 int ret = 0;
1092 int i;
1093
1094 if (insn->insn & INSN_MASK_SPECIAL) {
1095 /* a non-subdevice instruction */
1096
1097 switch (insn->insn) {
1098 case INSN_GTOD:
1099 {
1100 struct timeval tv;
1101
1102 if (insn->n != 2) {
1103 ret = -EINVAL;
1104 break;
1105 }
1106
1107 do_gettimeofday(&tv);
1108 data[0] = tv.tv_sec;
1109 data[1] = tv.tv_usec;
1110 ret = 2;
1111
1112 break;
1113 }
1114 case INSN_WAIT:
1115 if (insn->n != 1 || data[0] >= 100000) {
1116 ret = -EINVAL;
1117 break;
1118 }
1119 udelay(data[0] / 1000);
1120 ret = 1;
1121 break;
1122 case INSN_INTTRIG:
1123 if (insn->n != 1) {
1124 ret = -EINVAL;
1125 break;
1126 }
1127 if (insn->subdev >= dev->n_subdevices) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001128 dev_dbg(dev->class_dev,
1129 "%d not usable subdevice\n",
David Schleefed9eccb2008-11-04 20:29:31 -08001130 insn->subdev);
1131 ret = -EINVAL;
1132 break;
1133 }
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001134 s = &dev->subdevices[insn->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001135 if (!s->async) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001136 dev_dbg(dev->class_dev, "no async\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001137 ret = -EINVAL;
1138 break;
1139 }
1140 if (!s->async->inttrig) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001141 dev_dbg(dev->class_dev, "no inttrig\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001142 ret = -EAGAIN;
1143 break;
1144 }
Ian Abbott5d06e3d2012-09-18 19:46:58 +01001145 ret = s->async->inttrig(dev, s, data[0]);
David Schleefed9eccb2008-11-04 20:29:31 -08001146 if (ret >= 0)
1147 ret = 1;
1148 break;
1149 default:
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001150 dev_dbg(dev->class_dev, "invalid insn\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001151 ret = -EINVAL;
1152 break;
1153 }
1154 } else {
1155 /* a subdevice instruction */
Bill Pemberton790c5542009-03-16 22:05:02 -04001156 unsigned int maxdata;
David Schleefed9eccb2008-11-04 20:29:31 -08001157
1158 if (insn->subdev >= dev->n_subdevices) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001159 dev_dbg(dev->class_dev, "subdevice %d out of range\n",
1160 insn->subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001161 ret = -EINVAL;
1162 goto out;
1163 }
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001164 s = &dev->subdevices[insn->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001165
1166 if (s->type == COMEDI_SUBD_UNUSED) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001167 dev_dbg(dev->class_dev, "%d not usable subdevice\n",
1168 insn->subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001169 ret = -EIO;
1170 goto out;
1171 }
1172
1173 /* are we locked? (ioctl lock) */
1174 if (s->lock && s->lock != file) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001175 dev_dbg(dev->class_dev, "device locked\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001176 ret = -EACCES;
1177 goto out;
1178 }
1179
Greg Kroah-Hartman0fd0ca72010-05-01 12:33:17 -07001180 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001181 if (ret < 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001182 ret = -EINVAL;
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001183 dev_dbg(dev->class_dev, "bad chanspec\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001184 goto out;
1185 }
1186
1187 if (s->busy) {
1188 ret = -EBUSY;
1189 goto out;
1190 }
1191 /* This looks arbitrary. It is. */
1192 s->busy = &parse_insn;
1193 switch (insn->insn) {
1194 case INSN_READ:
1195 ret = s->insn_read(dev, s, insn, data);
H Hartley Sweeten22ca19d2014-02-10 11:49:45 -07001196 if (ret == -ETIMEDOUT) {
1197 dev_dbg(dev->class_dev,
1198 "subdevice %d read instruction timed out\n",
1199 s->index);
1200 }
David Schleefed9eccb2008-11-04 20:29:31 -08001201 break;
1202 case INSN_WRITE:
1203 maxdata = s->maxdata_list
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001204 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1205 : s->maxdata;
David Schleefed9eccb2008-11-04 20:29:31 -08001206 for (i = 0; i < insn->n; ++i) {
1207 if (data[i] > maxdata) {
1208 ret = -EINVAL;
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001209 dev_dbg(dev->class_dev,
1210 "bad data value(s)\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001211 break;
1212 }
1213 }
H Hartley Sweeten22ca19d2014-02-10 11:49:45 -07001214 if (ret == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001215 ret = s->insn_write(dev, s, insn, data);
H Hartley Sweeten22ca19d2014-02-10 11:49:45 -07001216 if (ret == -ETIMEDOUT) {
1217 dev_dbg(dev->class_dev,
1218 "subdevice %d write instruction timed out\n",
1219 s->index);
1220 }
1221 }
David Schleefed9eccb2008-11-04 20:29:31 -08001222 break;
1223 case INSN_BITS:
1224 if (insn->n != 2) {
1225 ret = -EINVAL;
Ian Abbott2f644cc2011-01-18 17:44:33 +00001226 } else {
1227 /* Most drivers ignore the base channel in
1228 * insn->chanspec. Fix this here if
1229 * the subdevice has <= 32 channels. */
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07001230 unsigned int orig_mask = data[0];
1231 unsigned int shift = 0;
Ian Abbott2f644cc2011-01-18 17:44:33 +00001232
Ian Abbott2f644cc2011-01-18 17:44:33 +00001233 if (s->n_chan <= 32) {
1234 shift = CR_CHAN(insn->chanspec);
1235 if (shift > 0) {
1236 insn->chanspec = 0;
1237 data[0] <<= shift;
1238 data[1] <<= shift;
1239 }
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07001240 }
Ian Abbott2f644cc2011-01-18 17:44:33 +00001241 ret = s->insn_bits(dev, s, insn, data);
1242 data[0] = orig_mask;
1243 if (shift > 0)
1244 data[1] >>= shift;
David Schleefed9eccb2008-11-04 20:29:31 -08001245 }
David Schleefed9eccb2008-11-04 20:29:31 -08001246 break;
1247 case INSN_CONFIG:
1248 ret = check_insn_config_length(insn, data);
1249 if (ret)
1250 break;
1251 ret = s->insn_config(dev, s, insn, data);
1252 break;
1253 default:
1254 ret = -EINVAL;
1255 break;
1256 }
1257
1258 s->busy = NULL;
1259 }
1260
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001261out:
David Schleefed9eccb2008-11-04 20:29:31 -08001262 return ret;
1263}
1264
1265/*
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001266 * COMEDI_INSNLIST
1267 * synchronous instructions
1268 *
1269 * arg:
1270 * pointer to sync cmd structure
1271 *
1272 * reads:
1273 * sync cmd struct at arg
1274 * instruction list
1275 * data (for writes)
1276 *
1277 * writes:
1278 * data (for reads)
1279 */
1280/* arbitrary limits */
1281#define MAX_SAMPLES 256
1282static int do_insnlist_ioctl(struct comedi_device *dev,
1283 struct comedi_insnlist __user *arg, void *file)
1284{
1285 struct comedi_insnlist insnlist;
1286 struct comedi_insn *insns = NULL;
1287 unsigned int *data = NULL;
1288 int i = 0;
1289 int ret = 0;
1290
1291 if (copy_from_user(&insnlist, arg, sizeof(insnlist)))
1292 return -EFAULT;
1293
Wolfgang Ockerf4a8f522014-06-02 22:48:06 +02001294 data = kmalloc_array(MAX_SAMPLES, sizeof(unsigned int), GFP_KERNEL);
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001295 if (!data) {
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001296 ret = -ENOMEM;
1297 goto error;
1298 }
1299
1300 insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
1301 if (!insns) {
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001302 ret = -ENOMEM;
1303 goto error;
1304 }
1305
1306 if (copy_from_user(insns, insnlist.insns,
1307 sizeof(*insns) * insnlist.n_insns)) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001308 dev_dbg(dev->class_dev, "copy_from_user failed\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001309 ret = -EFAULT;
1310 goto error;
1311 }
1312
1313 for (i = 0; i < insnlist.n_insns; i++) {
1314 if (insns[i].n > MAX_SAMPLES) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001315 dev_dbg(dev->class_dev,
1316 "number of samples too large\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001317 ret = -EINVAL;
1318 goto error;
1319 }
1320 if (insns[i].insn & INSN_MASK_WRITE) {
1321 if (copy_from_user(data, insns[i].data,
1322 insns[i].n * sizeof(unsigned int))) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001323 dev_dbg(dev->class_dev,
1324 "copy_from_user failed\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001325 ret = -EFAULT;
1326 goto error;
1327 }
1328 }
1329 ret = parse_insn(dev, insns + i, data, file);
1330 if (ret < 0)
1331 goto error;
1332 if (insns[i].insn & INSN_MASK_READ) {
1333 if (copy_to_user(insns[i].data, data,
1334 insns[i].n * sizeof(unsigned int))) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001335 dev_dbg(dev->class_dev,
1336 "copy_to_user failed\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001337 ret = -EFAULT;
1338 goto error;
1339 }
1340 }
1341 if (need_resched())
1342 schedule();
1343 }
1344
1345error:
1346 kfree(insns);
1347 kfree(data);
1348
1349 if (ret < 0)
1350 return ret;
1351 return i;
1352}
1353
1354/*
Pieter De Praetere20617f22010-03-10 09:47:44 +01001355 * COMEDI_INSN
1356 * synchronous instructions
David Schleefed9eccb2008-11-04 20:29:31 -08001357 *
Pieter De Praetere20617f22010-03-10 09:47:44 +01001358 * arg:
1359 * pointer to insn
David Schleefed9eccb2008-11-04 20:29:31 -08001360 *
Pieter De Praetere20617f22010-03-10 09:47:44 +01001361 * reads:
1362 * struct comedi_insn struct at arg
1363 * data (for writes)
David Schleefed9eccb2008-11-04 20:29:31 -08001364 *
Pieter De Praetere20617f22010-03-10 09:47:44 +01001365 * writes:
1366 * data (for reads)
David Schleefed9eccb2008-11-04 20:29:31 -08001367 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001368static int do_insn_ioctl(struct comedi_device *dev,
1369 struct comedi_insn __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001370{
Bill Pemberton90035c02009-03-16 22:05:53 -04001371 struct comedi_insn insn;
Bill Pemberton790c5542009-03-16 22:05:02 -04001372 unsigned int *data = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001373 int ret = 0;
1374
Wolfgang Ockerf4a8f522014-06-02 22:48:06 +02001375 data = kmalloc_array(MAX_SAMPLES, sizeof(unsigned int), GFP_KERNEL);
David Schleefed9eccb2008-11-04 20:29:31 -08001376 if (!data) {
1377 ret = -ENOMEM;
1378 goto error;
1379 }
1380
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001381 if (copy_from_user(&insn, arg, sizeof(insn))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001382 ret = -EFAULT;
1383 goto error;
1384 }
1385
1386 /* This is where the behavior of insn and insnlist deviate. */
1387 if (insn.n > MAX_SAMPLES)
1388 insn.n = MAX_SAMPLES;
1389 if (insn.insn & INSN_MASK_WRITE) {
Mark21fe2ee2010-05-13 17:44:39 +08001390 if (copy_from_user(data,
1391 insn.data,
1392 insn.n * sizeof(unsigned int))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001393 ret = -EFAULT;
1394 goto error;
1395 }
1396 }
1397 ret = parse_insn(dev, &insn, data, file);
1398 if (ret < 0)
1399 goto error;
1400 if (insn.insn & INSN_MASK_READ) {
Mark21fe2ee2010-05-13 17:44:39 +08001401 if (copy_to_user(insn.data,
1402 data,
1403 insn.n * sizeof(unsigned int))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001404 ret = -EFAULT;
1405 goto error;
1406 }
1407 }
1408 ret = insn.n;
1409
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001410error:
1411 kfree(data);
David Schleefed9eccb2008-11-04 20:29:31 -08001412
1413 return ret;
1414}
1415
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001416static int __comedi_get_user_cmd(struct comedi_device *dev,
1417 struct comedi_cmd __user *arg,
1418 struct comedi_cmd *cmd)
1419{
1420 struct comedi_subdevice *s;
1421
1422 if (copy_from_user(cmd, arg, sizeof(*cmd))) {
1423 dev_dbg(dev->class_dev, "bad cmd address\n");
1424 return -EFAULT;
1425 }
1426
1427 if (cmd->subdev >= dev->n_subdevices) {
1428 dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev);
1429 return -ENODEV;
1430 }
1431
1432 s = &dev->subdevices[cmd->subdev];
1433
1434 if (s->type == COMEDI_SUBD_UNUSED) {
Yves Deweerdtb2f48742014-03-31 22:55:39 +02001435 dev_dbg(dev->class_dev, "%d not valid subdevice\n",
1436 cmd->subdev);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001437 return -EIO;
1438 }
1439
1440 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1441 dev_dbg(dev->class_dev,
Yves Deweerdtb2f48742014-03-31 22:55:39 +02001442 "subdevice %d does not support commands\n",
1443 cmd->subdev);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001444 return -EIO;
1445 }
1446
1447 /* make sure channel/gain list isn't too long */
1448 if (cmd->chanlist_len > s->len_chanlist) {
1449 dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n",
1450 cmd->chanlist_len, s->len_chanlist);
1451 return -EINVAL;
1452 }
1453
1454 return 0;
1455}
1456
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001457static int __comedi_get_user_chanlist(struct comedi_device *dev,
1458 struct comedi_subdevice *s,
1459 unsigned int __user *user_chanlist,
1460 struct comedi_cmd *cmd)
1461{
1462 unsigned int *chanlist;
1463 int ret;
1464
1465 /* user_chanlist could be NULL for do_cmdtest ioctls */
1466 if (!user_chanlist)
1467 return 0;
1468
1469 chanlist = memdup_user(user_chanlist,
1470 cmd->chanlist_len * sizeof(unsigned int));
1471 if (IS_ERR(chanlist))
1472 return PTR_ERR(chanlist);
1473
1474 /* make sure each element in channel/gain list is valid */
1475 ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist);
1476 if (ret < 0) {
1477 kfree(chanlist);
1478 return ret;
1479 }
1480
1481 cmd->chanlist = chanlist;
1482
1483 return 0;
1484}
1485
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001486static int do_cmd_ioctl(struct comedi_device *dev,
H Hartley Sweetencbe01f72012-09-18 11:41:54 -07001487 struct comedi_cmd __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001488{
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001489 struct comedi_cmd cmd;
Bill Pemberton34c43922009-03-16 22:05:14 -04001490 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04001491 struct comedi_async *async;
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001492 unsigned int __user *user_chanlist;
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001493 int ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001494
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001495 /* get the user's cmd and do some simple validation */
1496 ret = __comedi_get_user_cmd(dev, arg, &cmd);
1497 if (ret)
1498 return ret;
1499
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001500 /* save user's chanlist pointer so it can be restored later */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001501 user_chanlist = (unsigned int __user *)cmd.chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001502
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001503 s = &dev->subdevices[cmd.subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001504 async = s->async;
1505
David Schleefed9eccb2008-11-04 20:29:31 -08001506 /* are we locked? (ioctl lock) */
1507 if (s->lock && s->lock != file) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001508 dev_dbg(dev->class_dev, "subdevice locked\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001509 return -EACCES;
1510 }
1511
1512 /* are we busy? */
1513 if (s->busy) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001514 dev_dbg(dev->class_dev, "subdevice busy\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001515 return -EBUSY;
1516 }
David Schleefed9eccb2008-11-04 20:29:31 -08001517
David Schleefed9eccb2008-11-04 20:29:31 -08001518 /* make sure channel/gain list isn't too short */
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001519 if (cmd.chanlist_len < 1) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001520 dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n",
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001521 cmd.chanlist_len);
Ian Abbott4b18f082013-07-05 16:49:34 +01001522 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001523 }
1524
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001525 async->cmd = cmd;
David Schleefed9eccb2008-11-04 20:29:31 -08001526 async->cmd.data = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001527
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001528 /* load channel/gain list */
1529 ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd);
1530 if (ret)
David Schleefed9eccb2008-11-04 20:29:31 -08001531 goto cleanup;
David Schleefed9eccb2008-11-04 20:29:31 -08001532
1533 ret = s->do_cmdtest(dev, s, &async->cmd);
1534
1535 if (async->cmd.flags & TRIG_BOGUS || ret) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001536 dev_dbg(dev->class_dev, "test returned %d\n", ret);
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001537 cmd = async->cmd;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001538 /* restore chanlist pointer before copying back */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001539 cmd.chanlist = (unsigned int __force *)user_chanlist;
H Hartley Sweeten88bc0572012-09-18 11:42:37 -07001540 cmd.data = NULL;
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001541 if (copy_to_user(arg, &cmd, sizeof(cmd))) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001542 dev_dbg(dev->class_dev, "fault writing cmd\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001543 ret = -EFAULT;
1544 goto cleanup;
1545 }
1546 ret = -EAGAIN;
1547 goto cleanup;
1548 }
1549
1550 if (!async->prealloc_bufsz) {
1551 ret = -ENOMEM;
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001552 dev_dbg(dev->class_dev, "no buffer (?)\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001553 goto cleanup;
1554 }
1555
Ian Abbottfcc18a92014-05-06 13:12:10 +01001556 comedi_buf_reset(s);
David Schleefed9eccb2008-11-04 20:29:31 -08001557
1558 async->cb_mask =
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001559 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1560 COMEDI_CB_OVERFLOW;
Ian Abbottd8bff6e2014-09-03 13:45:30 +01001561 if (async->cmd.flags & CMDF_WAKE_EOS)
David Schleefed9eccb2008-11-04 20:29:31 -08001562 async->cb_mask |= COMEDI_CB_EOS;
David Schleefed9eccb2008-11-04 20:29:31 -08001563
Ian Abbottc265be02013-11-08 15:03:22 +00001564 comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING);
David Schleefed9eccb2008-11-04 20:29:31 -08001565
Ian Abbott4b18f082013-07-05 16:49:34 +01001566 /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
1567 * comedi_read() or comedi_write() */
1568 s->busy = file;
David Schleefed9eccb2008-11-04 20:29:31 -08001569 ret = s->do_cmd(dev, s);
1570 if (ret == 0)
1571 return 0;
1572
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001573cleanup:
David Schleefed9eccb2008-11-04 20:29:31 -08001574 do_become_nonbusy(dev, s);
1575
1576 return ret;
1577}
1578
1579/*
1580 COMEDI_CMDTEST
1581 command testing ioctl
1582
1583 arg:
1584 pointer to cmd structure
1585
1586 reads:
1587 cmd structure at arg
1588 channel/range list
1589
1590 writes:
1591 modified cmd structure at arg
1592
1593*/
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001594static int do_cmdtest_ioctl(struct comedi_device *dev,
1595 struct comedi_cmd __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001596{
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001597 struct comedi_cmd cmd;
Bill Pemberton34c43922009-03-16 22:05:14 -04001598 struct comedi_subdevice *s;
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001599 unsigned int __user *user_chanlist;
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001600 int ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001601
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001602 /* get the user's cmd and do some simple validation */
1603 ret = __comedi_get_user_cmd(dev, arg, &cmd);
1604 if (ret)
1605 return ret;
1606
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001607 /* save user's chanlist pointer so it can be restored later */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001608 user_chanlist = (unsigned int __user *)cmd.chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001609
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001610 s = &dev->subdevices[cmd.subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001611
1612 /* load channel/gain list */
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001613 ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
1614 if (ret)
1615 return ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001616
H Hartley Sweetenf8348672012-09-18 11:43:13 -07001617 ret = s->do_cmdtest(dev, s, &cmd);
David Schleefed9eccb2008-11-04 20:29:31 -08001618
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001619 /* restore chanlist pointer before copying back */
H Hartley Sweeten95bc3592012-09-18 11:43:52 -07001620 cmd.chanlist = (unsigned int __force *)user_chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001621
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001622 if (copy_to_user(arg, &cmd, sizeof(cmd))) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001623 dev_dbg(dev->class_dev, "bad cmd address\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001624 ret = -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -08001625 }
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001626
David Schleefed9eccb2008-11-04 20:29:31 -08001627 return ret;
1628}
1629
1630/*
1631 COMEDI_LOCK
1632 lock subdevice
1633
1634 arg:
1635 subdevice number
1636
1637 reads:
1638 none
1639
1640 writes:
1641 none
1642
1643*/
1644
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301645static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1646 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001647{
1648 int ret = 0;
1649 unsigned long flags;
Bill Pemberton34c43922009-03-16 22:05:14 -04001650 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001651
1652 if (arg >= dev->n_subdevices)
1653 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001654 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001655
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001656 spin_lock_irqsave(&s->spin_lock, flags);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001657 if (s->busy || s->lock)
David Schleefed9eccb2008-11-04 20:29:31 -08001658 ret = -EBUSY;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001659 else
David Schleefed9eccb2008-11-04 20:29:31 -08001660 s->lock = file;
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001661 spin_unlock_irqrestore(&s->spin_lock, flags);
David Schleefed9eccb2008-11-04 20:29:31 -08001662
David Schleefed9eccb2008-11-04 20:29:31 -08001663 return ret;
1664}
1665
1666/*
1667 COMEDI_UNLOCK
1668 unlock subdevice
1669
1670 arg:
1671 subdevice number
1672
1673 reads:
1674 none
1675
1676 writes:
1677 none
1678
1679 This function isn't protected by the semaphore, since
1680 we already own the lock.
1681*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301682static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1683 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001684{
Bill Pemberton34c43922009-03-16 22:05:14 -04001685 struct comedi_subdevice *s;
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
1691 if (s->busy)
1692 return -EBUSY;
1693
1694 if (s->lock && s->lock != file)
1695 return -EACCES;
1696
H Hartley Sweeten90ac0762014-07-21 11:01:26 -07001697 if (s->lock == file)
David Schleefed9eccb2008-11-04 20:29:31 -08001698 s->lock = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001699
1700 return 0;
1701}
1702
1703/*
1704 COMEDI_CANCEL
1705 cancel acquisition ioctl
1706
1707 arg:
1708 subdevice number
1709
1710 reads:
1711 nothing
1712
1713 writes:
1714 nothing
1715
1716*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301717static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1718 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001719{
Bill Pemberton34c43922009-03-16 22:05:14 -04001720 struct comedi_subdevice *s;
Ian Abbott69acbaa2013-07-08 13:36:19 +01001721 int ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001722
1723 if (arg >= dev->n_subdevices)
1724 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001725 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001726 if (s->async == NULL)
1727 return -EINVAL;
1728
David Schleefed9eccb2008-11-04 20:29:31 -08001729 if (!s->busy)
1730 return 0;
1731
1732 if (s->busy != file)
1733 return -EBUSY;
1734
Ian Abbott69acbaa2013-07-08 13:36:19 +01001735 ret = do_cancel(dev, s);
Ian Abbott69acbaa2013-07-08 13:36:19 +01001736
1737 return ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001738}
1739
1740/*
1741 COMEDI_POLL ioctl
1742 instructs driver to synchronize buffers
1743
1744 arg:
1745 subdevice number
1746
1747 reads:
1748 nothing
1749
1750 writes:
1751 nothing
1752
1753*/
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301754static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1755 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001756{
Bill Pemberton34c43922009-03-16 22:05:14 -04001757 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001758
1759 if (arg >= dev->n_subdevices)
1760 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001761 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001762
David Schleefed9eccb2008-11-04 20:29:31 -08001763 if (!s->busy)
1764 return 0;
1765
1766 if (s->busy != file)
1767 return -EBUSY;
1768
1769 if (s->poll)
1770 return s->poll(dev, s);
1771
1772 return -EINVAL;
1773}
1774
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001775static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
1776 unsigned long arg)
1777{
Al Viro6131ffa2013-02-27 16:59:05 -05001778 const unsigned minor = iminor(file_inode(file));
Ian Abbotte5d670d2013-11-08 15:03:40 +00001779 struct comedi_device *dev = file->private_data;
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001780 int rc;
1781
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001782 mutex_lock(&dev->mutex);
1783
1784 /* Device config is special, because it must work on
1785 * an unconfigured device. */
1786 if (cmd == COMEDI_DEVCONFIG) {
Ian Abbott754ab5c2013-01-28 16:14:31 +00001787 if (minor >= COMEDI_NUM_BOARD_MINORS) {
1788 /* Device config not appropriate on non-board minors. */
1789 rc = -ENOTTY;
1790 goto done;
1791 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001792 rc = do_devconfig_ioctl(dev,
1793 (struct comedi_devconfig __user *)arg);
Ian Abbott8ab4ed62013-04-04 14:58:54 +01001794 if (rc == 0) {
1795 if (arg == 0 &&
1796 dev->minor >= comedi_num_legacy_minors) {
1797 /* Successfully unconfigured a dynamically
1798 * allocated device. Try and remove it. */
Ian Abbottdb210da2013-04-04 14:59:18 +01001799 if (comedi_clear_board_dev(dev)) {
Ian Abbott8ab4ed62013-04-04 14:58:54 +01001800 mutex_unlock(&dev->mutex);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01001801 comedi_free_board_dev(dev);
Ian Abbott8ab4ed62013-04-04 14:58:54 +01001802 return rc;
1803 }
1804 }
1805 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001806 goto done;
1807 }
1808
1809 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001810 dev_dbg(dev->class_dev, "no driver attached\n");
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07001811 rc = -ENODEV;
1812 goto done;
1813 }
1814
1815 switch (cmd) {
1816 case COMEDI_BUFCONFIG:
1817 rc = do_bufconfig_ioctl(dev,
1818 (struct comedi_bufconfig __user *)arg);
1819 break;
1820 case COMEDI_DEVINFO:
1821 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
1822 file);
1823 break;
1824 case COMEDI_SUBDINFO:
1825 rc = do_subdinfo_ioctl(dev,
1826 (struct comedi_subdinfo __user *)arg,
1827 file);
1828 break;
1829 case COMEDI_CHANINFO:
1830 rc = do_chaninfo_ioctl(dev, (void __user *)arg);
1831 break;
1832 case COMEDI_RANGEINFO:
1833 rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
1834 break;
1835 case COMEDI_BUFINFO:
1836 rc = do_bufinfo_ioctl(dev,
1837 (struct comedi_bufinfo __user *)arg,
1838 file);
1839 break;
1840 case COMEDI_LOCK:
1841 rc = do_lock_ioctl(dev, arg, file);
1842 break;
1843 case COMEDI_UNLOCK:
1844 rc = do_unlock_ioctl(dev, arg, file);
1845 break;
1846 case COMEDI_CANCEL:
1847 rc = do_cancel_ioctl(dev, arg, file);
1848 break;
1849 case COMEDI_CMD:
1850 rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
1851 break;
1852 case COMEDI_CMDTEST:
1853 rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
1854 file);
1855 break;
1856 case COMEDI_INSNLIST:
1857 rc = do_insnlist_ioctl(dev,
1858 (struct comedi_insnlist __user *)arg,
1859 file);
1860 break;
1861 case COMEDI_INSN:
1862 rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
1863 file);
1864 break;
1865 case COMEDI_POLL:
1866 rc = do_poll_ioctl(dev, arg, file);
1867 break;
1868 default:
1869 rc = -ENOTTY;
1870 break;
1871 }
1872
1873done:
1874 mutex_unlock(&dev->mutex);
1875 return rc;
1876}
1877
Federico Vagadf30b212011-10-29 09:45:39 +02001878static void comedi_vm_open(struct vm_area_struct *area)
1879{
Ian Abbottaf93da32013-11-08 15:03:43 +00001880 struct comedi_buf_map *bm;
Federico Vagadf30b212011-10-29 09:45:39 +02001881
Ian Abbottaf93da32013-11-08 15:03:43 +00001882 bm = area->vm_private_data;
1883 comedi_buf_map_get(bm);
Federico Vagadf30b212011-10-29 09:45:39 +02001884}
1885
1886static void comedi_vm_close(struct vm_area_struct *area)
David Schleefed9eccb2008-11-04 20:29:31 -08001887{
Ian Abbottaf93da32013-11-08 15:03:43 +00001888 struct comedi_buf_map *bm;
David Schleefed9eccb2008-11-04 20:29:31 -08001889
Ian Abbottaf93da32013-11-08 15:03:43 +00001890 bm = area->vm_private_data;
1891 comedi_buf_map_put(bm);
David Schleefed9eccb2008-11-04 20:29:31 -08001892}
1893
1894static struct vm_operations_struct comedi_vm_ops = {
Federico Vagadf30b212011-10-29 09:45:39 +02001895 .open = comedi_vm_open,
1896 .close = comedi_vm_close,
David Schleefed9eccb2008-11-04 20:29:31 -08001897};
1898
1899static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1900{
Al Viro6131ffa2013-02-27 16:59:05 -05001901 const unsigned minor = iminor(file_inode(file));
Ian Abbotte5d670d2013-11-08 15:03:40 +00001902 struct comedi_device *dev = file->private_data;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001903 struct comedi_subdevice *s;
1904 struct comedi_async *async;
Ian Abbottb34aa862014-04-10 19:41:57 +01001905 struct comedi_buf_map *bm = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001906 unsigned long start = vma->vm_start;
1907 unsigned long size;
1908 int n_pages;
1909 int i;
1910 int retval;
Bernd Porr3ffab422011-11-08 21:23:03 +00001911
Ian Abbottb34aa862014-04-10 19:41:57 +01001912 /*
1913 * 'trylock' avoids circular dependency with current->mm->mmap_sem
1914 * and down-reading &dev->attach_lock should normally succeed without
1915 * contention unless the device is in the process of being attached
1916 * or detached.
1917 */
1918 if (!down_read_trylock(&dev->attach_lock))
1919 return -EAGAIN;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001920
David Schleefed9eccb2008-11-04 20:29:31 -08001921 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001922 dev_dbg(dev->class_dev, "no driver attached\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001923 retval = -ENODEV;
1924 goto done;
1925 }
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001926
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001927 if (vma->vm_flags & VM_WRITE)
Ian Abbottda56fdc2013-04-04 14:59:10 +01001928 s = comedi_write_subdevice(dev, minor);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001929 else
Ian Abbottda56fdc2013-04-04 14:59:10 +01001930 s = comedi_read_subdevice(dev, minor);
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001931 if (!s) {
David Schleefed9eccb2008-11-04 20:29:31 -08001932 retval = -EINVAL;
1933 goto done;
1934 }
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001935
David Schleefed9eccb2008-11-04 20:29:31 -08001936 async = s->async;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001937 if (!async) {
David Schleefed9eccb2008-11-04 20:29:31 -08001938 retval = -EINVAL;
1939 goto done;
1940 }
1941
1942 if (vma->vm_pgoff != 0) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001943 dev_dbg(dev->class_dev, "mmap() offset must be 0.\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001944 retval = -EINVAL;
1945 goto done;
1946 }
1947
1948 size = vma->vm_end - vma->vm_start;
1949 if (size > async->prealloc_bufsz) {
1950 retval = -EFAULT;
1951 goto done;
1952 }
1953 if (size & (~PAGE_MASK)) {
1954 retval = -EFAULT;
1955 goto done;
1956 }
1957
1958 n_pages = size >> PAGE_SHIFT;
Ian Abbottb34aa862014-04-10 19:41:57 +01001959
1960 /* get reference to current buf map (if any) */
1961 bm = comedi_buf_map_from_subdev_get(s);
Ian Abbottaf93da32013-11-08 15:03:43 +00001962 if (!bm || n_pages > bm->n_pages) {
1963 retval = -EINVAL;
1964 goto done;
1965 }
David Schleefed9eccb2008-11-04 20:29:31 -08001966 for (i = 0; i < n_pages; ++i) {
Ian Abbottaf93da32013-11-08 15:03:43 +00001967 struct comedi_buf_page *buf = &bm->page_list[i];
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001968
David Schleefed9eccb2008-11-04 20:29:31 -08001969 if (remap_pfn_range(vma, start,
H Hartley Sweetena52840a2012-12-19 15:45:12 -07001970 page_to_pfn(virt_to_page(buf->virt_addr)),
1971 PAGE_SIZE, PAGE_SHARED)) {
David Schleefed9eccb2008-11-04 20:29:31 -08001972 retval = -EAGAIN;
1973 goto done;
1974 }
1975 start += PAGE_SIZE;
1976 }
1977
1978 vma->vm_ops = &comedi_vm_ops;
Ian Abbottaf93da32013-11-08 15:03:43 +00001979 vma->vm_private_data = bm;
David Schleefed9eccb2008-11-04 20:29:31 -08001980
Ian Abbottaf93da32013-11-08 15:03:43 +00001981 vma->vm_ops->open(vma);
David Schleefed9eccb2008-11-04 20:29:31 -08001982
1983 retval = 0;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001984done:
Ian Abbottb34aa862014-04-10 19:41:57 +01001985 up_read(&dev->attach_lock);
1986 comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
David Schleefed9eccb2008-11-04 20:29:31 -08001987 return retval;
1988}
1989
Benedikt Bergenthal1ae50622012-04-16 12:40:22 +02001990static unsigned int comedi_poll(struct file *file, poll_table *wait)
David Schleefed9eccb2008-11-04 20:29:31 -08001991{
1992 unsigned int mask = 0;
Al Viro6131ffa2013-02-27 16:59:05 -05001993 const unsigned minor = iminor(file_inode(file));
Ian Abbotte5d670d2013-11-08 15:03:40 +00001994 struct comedi_device *dev = file->private_data;
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001995 struct comedi_subdevice *s;
Bernd Porr3ffab422011-11-08 21:23:03 +00001996
David Schleefed9eccb2008-11-04 20:29:31 -08001997 mutex_lock(&dev->mutex);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07001998
David Schleefed9eccb2008-11-04 20:29:31 -08001999 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002000 dev_dbg(dev->class_dev, "no driver attached\n");
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002001 goto done;
David Schleefed9eccb2008-11-04 20:29:31 -08002002 }
2003
Ian Abbottda56fdc2013-04-04 14:59:10 +01002004 s = comedi_read_subdevice(dev, minor);
Ian Abbottcc400e12013-02-05 12:50:40 +00002005 if (s && s->async) {
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002006 poll_wait(file, &s->async->wait_head, wait);
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002007 if (!s->busy || !comedi_is_subdevice_running(s) ||
Ian Abbotte9edef32014-05-06 13:12:09 +01002008 comedi_buf_read_n_available(s) > 0)
David Schleefed9eccb2008-11-04 20:29:31 -08002009 mask |= POLLIN | POLLRDNORM;
David Schleefed9eccb2008-11-04 20:29:31 -08002010 }
2011
Ian Abbottda56fdc2013-04-04 14:59:10 +01002012 s = comedi_write_subdevice(dev, minor);
Ian Abbottcc400e12013-02-05 12:50:40 +00002013 if (s && s->async) {
Ian Abbott0ce016d2014-05-02 13:50:13 +01002014 unsigned int bps = bytes_per_sample(s);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002015
2016 poll_wait(file, &s->async->wait_head, wait);
Ian Abbott24e894b2014-05-06 13:12:04 +01002017 comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002018 if (!s->busy || !comedi_is_subdevice_running(s) ||
Ian Abbott0f1f34e2014-05-06 13:12:06 +01002019 comedi_buf_write_n_allocated(s) >= bps)
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002020 mask |= POLLOUT | POLLWRNORM;
2021 }
2022
2023done:
David Schleefed9eccb2008-11-04 20:29:31 -08002024 mutex_unlock(&dev->mutex);
2025 return mask;
2026}
2027
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07002028static ssize_t comedi_write(struct file *file, const char __user *buf,
2029 size_t nbytes, loff_t *offset)
David Schleefed9eccb2008-11-04 20:29:31 -08002030{
Bill Pemberton34c43922009-03-16 22:05:14 -04002031 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04002032 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -08002033 int n, m, count = 0, retval = 0;
2034 DECLARE_WAITQUEUE(wait, current);
Al Viro6131ffa2013-02-27 16:59:05 -05002035 const unsigned minor = iminor(file_inode(file));
Ian Abbotte5d670d2013-11-08 15:03:40 +00002036 struct comedi_device *dev = file->private_data;
Ian Abbott9329f132013-11-08 15:03:30 +00002037 bool on_wait_queue = false;
2038 bool attach_locked;
2039 unsigned int old_detach_count;
Bernd Porr3ffab422011-11-08 21:23:03 +00002040
Ian Abbott9329f132013-11-08 15:03:30 +00002041 /* Protect against device detachment during operation. */
2042 down_read(&dev->attach_lock);
2043 attach_locked = true;
2044 old_detach_count = dev->detach_count;
2045
David Schleefed9eccb2008-11-04 20:29:31 -08002046 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002047 dev_dbg(dev->class_dev, "no driver attached\n");
Ian Abbott9329f132013-11-08 15:03:30 +00002048 retval = -ENODEV;
2049 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002050 }
2051
Ian Abbottda56fdc2013-04-04 14:59:10 +01002052 s = comedi_write_subdevice(dev, minor);
Ian Abbott9329f132013-11-08 15:03:30 +00002053 if (!s || !s->async) {
2054 retval = -EIO;
2055 goto out;
2056 }
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002057
David Schleefed9eccb2008-11-04 20:29:31 -08002058 async = s->async;
2059
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002060 if (!s->busy || !nbytes)
Ian Abbott9329f132013-11-08 15:03:30 +00002061 goto out;
2062 if (s->busy != file) {
2063 retval = -EACCES;
2064 goto out;
2065 }
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002066
David Schleefed9eccb2008-11-04 20:29:31 -08002067 add_wait_queue(&async->wait_head, &wait);
Ian Abbott9329f132013-11-08 15:03:30 +00002068 on_wait_queue = true;
David Schleefed9eccb2008-11-04 20:29:31 -08002069 while (nbytes > 0 && !retval) {
2070 set_current_state(TASK_INTERRUPTIBLE);
2071
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002072 if (!comedi_is_subdevice_running(s)) {
Ian Abbottd2611542010-05-19 17:22:41 +01002073 if (count == 0) {
Ian Abbott9329f132013-11-08 15:03:30 +00002074 struct comedi_subdevice *new_s;
2075
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002076 if (comedi_is_subdevice_in_error(s))
Ian Abbottd2611542010-05-19 17:22:41 +01002077 retval = -EPIPE;
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002078 else
Ian Abbottd2611542010-05-19 17:22:41 +01002079 retval = 0;
Ian Abbott9329f132013-11-08 15:03:30 +00002080 /*
2081 * To avoid deadlock, cannot acquire dev->mutex
2082 * while dev->attach_lock is held. Need to
2083 * remove task from the async wait queue before
2084 * releasing dev->attach_lock, as it might not
2085 * be valid afterwards.
2086 */
2087 remove_wait_queue(&async->wait_head, &wait);
2088 on_wait_queue = false;
2089 up_read(&dev->attach_lock);
2090 attach_locked = false;
2091 mutex_lock(&dev->mutex);
2092 /*
2093 * Become non-busy unless things have changed
2094 * behind our back. Checking dev->detach_count
2095 * is unchanged ought to be sufficient (unless
2096 * there have been 2**32 detaches in the
2097 * meantime!), but check the subdevice pointer
2098 * as well just in case.
2099 */
2100 new_s = comedi_write_subdevice(dev, minor);
2101 if (dev->attached &&
2102 old_detach_count == dev->detach_count &&
2103 s == new_s && new_s->async == async)
2104 do_become_nonbusy(dev, s);
Ian Abbott4b18f082013-07-05 16:49:34 +01002105 mutex_unlock(&dev->mutex);
Ian Abbottd2611542010-05-19 17:22:41 +01002106 }
2107 break;
2108 }
2109
David Schleefed9eccb2008-11-04 20:29:31 -08002110 n = nbytes;
2111
2112 m = n;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002113 if (async->buf_write_ptr + m > async->prealloc_bufsz)
David Schleefed9eccb2008-11-04 20:29:31 -08002114 m = async->prealloc_bufsz - async->buf_write_ptr;
Ian Abbott24e894b2014-05-06 13:12:04 +01002115 comedi_buf_write_alloc(s, async->prealloc_bufsz);
Ian Abbott0f1f34e2014-05-06 13:12:06 +01002116 if (m > comedi_buf_write_n_allocated(s))
2117 m = comedi_buf_write_n_allocated(s);
David Schleefed9eccb2008-11-04 20:29:31 -08002118 if (m < n)
2119 n = m;
2120
2121 if (n == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08002122 if (file->f_flags & O_NONBLOCK) {
2123 retval = -EAGAIN;
2124 break;
2125 }
Federico Vaga6a9ce6b2011-10-29 09:47:39 +02002126 schedule();
David Schleefed9eccb2008-11-04 20:29:31 -08002127 if (signal_pending(current)) {
2128 retval = -ERESTARTSYS;
2129 break;
2130 }
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002131 if (!s->busy)
David Schleefed9eccb2008-11-04 20:29:31 -08002132 break;
David Schleefed9eccb2008-11-04 20:29:31 -08002133 if (s->busy != file) {
2134 retval = -EACCES;
2135 break;
2136 }
2137 continue;
2138 }
2139
2140 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002141 buf, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002142 if (m) {
2143 n -= m;
2144 retval = -EFAULT;
2145 }
Ian Abbott940dd352014-05-06 13:12:05 +01002146 comedi_buf_write_free(s, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002147
2148 count += n;
2149 nbytes -= n;
2150
2151 buf += n;
2152 break; /* makes device work like a pipe */
2153 }
Ian Abbott9329f132013-11-08 15:03:30 +00002154out:
2155 if (on_wait_queue)
2156 remove_wait_queue(&async->wait_head, &wait);
David Schleefed9eccb2008-11-04 20:29:31 -08002157 set_current_state(TASK_RUNNING);
Ian Abbott9329f132013-11-08 15:03:30 +00002158 if (attach_locked)
2159 up_read(&dev->attach_lock);
David Schleefed9eccb2008-11-04 20:29:31 -08002160
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002161 return count ? count : retval;
David Schleefed9eccb2008-11-04 20:29:31 -08002162}
2163
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07002164static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07002165 loff_t *offset)
David Schleefed9eccb2008-11-04 20:29:31 -08002166{
Bill Pemberton34c43922009-03-16 22:05:14 -04002167 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04002168 struct comedi_async *async;
David Schleefed9eccb2008-11-04 20:29:31 -08002169 int n, m, count = 0, retval = 0;
2170 DECLARE_WAITQUEUE(wait, current);
Al Viro6131ffa2013-02-27 16:59:05 -05002171 const unsigned minor = iminor(file_inode(file));
Ian Abbotte5d670d2013-11-08 15:03:40 +00002172 struct comedi_device *dev = file->private_data;
Ian Abbott45c2bc52013-11-08 15:03:31 +00002173 unsigned int old_detach_count;
2174 bool become_nonbusy = false;
2175 bool attach_locked;
Bernd Porr3ffab422011-11-08 21:23:03 +00002176
Ian Abbott45c2bc52013-11-08 15:03:31 +00002177 /* Protect against device detachment during operation. */
2178 down_read(&dev->attach_lock);
2179 attach_locked = true;
2180 old_detach_count = dev->detach_count;
2181
David Schleefed9eccb2008-11-04 20:29:31 -08002182 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002183 dev_dbg(dev->class_dev, "no driver attached\n");
Ian Abbott45c2bc52013-11-08 15:03:31 +00002184 retval = -ENODEV;
2185 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002186 }
2187
Ian Abbottda56fdc2013-04-04 14:59:10 +01002188 s = comedi_read_subdevice(dev, minor);
Ian Abbott45c2bc52013-11-08 15:03:31 +00002189 if (!s || !s->async) {
2190 retval = -EIO;
2191 goto out;
2192 }
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002193
David Schleefed9eccb2008-11-04 20:29:31 -08002194 async = s->async;
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002195 if (!s->busy || !nbytes)
Ian Abbott45c2bc52013-11-08 15:03:31 +00002196 goto out;
2197 if (s->busy != file) {
2198 retval = -EACCES;
2199 goto out;
2200 }
David Schleefed9eccb2008-11-04 20:29:31 -08002201
2202 add_wait_queue(&async->wait_head, &wait);
2203 while (nbytes > 0 && !retval) {
2204 set_current_state(TASK_INTERRUPTIBLE);
2205
2206 n = nbytes;
2207
Ian Abbotte9edef32014-05-06 13:12:09 +01002208 m = comedi_buf_read_n_available(s);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002209 if (async->buf_read_ptr + m > async->prealloc_bufsz)
David Schleefed9eccb2008-11-04 20:29:31 -08002210 m = async->prealloc_bufsz - async->buf_read_ptr;
David Schleefed9eccb2008-11-04 20:29:31 -08002211 if (m < n)
2212 n = m;
2213
2214 if (n == 0) {
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002215 if (!comedi_is_subdevice_running(s)) {
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002216 if (comedi_is_subdevice_in_error(s))
David Schleefed9eccb2008-11-04 20:29:31 -08002217 retval = -EPIPE;
H Hartley Sweetenc098c21a2012-12-19 15:44:02 -07002218 else
David Schleefed9eccb2008-11-04 20:29:31 -08002219 retval = 0;
Ian Abbott45c2bc52013-11-08 15:03:31 +00002220 become_nonbusy = true;
David Schleefed9eccb2008-11-04 20:29:31 -08002221 break;
2222 }
2223 if (file->f_flags & O_NONBLOCK) {
2224 retval = -EAGAIN;
2225 break;
2226 }
Federico Vaga6a9ce6b2011-10-29 09:47:39 +02002227 schedule();
David Schleefed9eccb2008-11-04 20:29:31 -08002228 if (signal_pending(current)) {
2229 retval = -ERESTARTSYS;
2230 break;
2231 }
David Schleefed9eccb2008-11-04 20:29:31 -08002232 if (!s->busy) {
2233 retval = 0;
2234 break;
2235 }
2236 if (s->busy != file) {
2237 retval = -EACCES;
2238 break;
2239 }
2240 continue;
2241 }
2242 m = copy_to_user(buf, async->prealloc_buf +
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002243 async->buf_read_ptr, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002244 if (m) {
2245 n -= m;
2246 retval = -EFAULT;
2247 }
2248
Ian Abbottd13be552014-05-06 13:12:07 +01002249 comedi_buf_read_alloc(s, n);
Ian Abbottf1df8662014-05-06 13:12:08 +01002250 comedi_buf_read_free(s, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002251
2252 count += n;
2253 nbytes -= n;
2254
2255 buf += n;
2256 break; /* makes device work like a pipe */
2257 }
Ian Abbott45c2bc52013-11-08 15:03:31 +00002258 remove_wait_queue(&async->wait_head, &wait);
2259 set_current_state(TASK_RUNNING);
2260 if (become_nonbusy || comedi_is_subdevice_idle(s)) {
2261 struct comedi_subdevice *new_s;
2262
2263 /*
2264 * To avoid deadlock, cannot acquire dev->mutex
2265 * while dev->attach_lock is held.
2266 */
2267 up_read(&dev->attach_lock);
2268 attach_locked = false;
Ian Abbott4b18f082013-07-05 16:49:34 +01002269 mutex_lock(&dev->mutex);
Ian Abbott45c2bc52013-11-08 15:03:31 +00002270 /*
2271 * Check device hasn't become detached behind our back.
2272 * Checking dev->detach_count is unchanged ought to be
2273 * sufficient (unless there have been 2**32 detaches in the
2274 * meantime!), but check the subdevice pointer as well just in
2275 * case.
2276 */
2277 new_s = comedi_read_subdevice(dev, minor);
2278 if (dev->attached && old_detach_count == dev->detach_count &&
2279 s == new_s && new_s->async == async) {
H Hartley Sweetenf4f3f7c2014-06-20 10:58:28 -07002280 if (become_nonbusy || comedi_buf_n_bytes_ready(s) == 0)
Ian Abbott45c2bc52013-11-08 15:03:31 +00002281 do_become_nonbusy(dev, s);
2282 }
Ian Abbott4b18f082013-07-05 16:49:34 +01002283 mutex_unlock(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002284 }
Ian Abbott45c2bc52013-11-08 15:03:31 +00002285out:
2286 if (attach_locked)
2287 up_read(&dev->attach_lock);
David Schleefed9eccb2008-11-04 20:29:31 -08002288
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002289 return count ? count : retval;
David Schleefed9eccb2008-11-04 20:29:31 -08002290}
2291
David Schleefed9eccb2008-11-04 20:29:31 -08002292static int comedi_open(struct inode *inode, struct file *file)
2293{
David Schleefed9eccb2008-11-04 20:29:31 -08002294 const unsigned minor = iminor(inode);
Ian Abbottfc406982013-11-08 15:03:34 +00002295 struct comedi_device *dev = comedi_dev_get_from_minor(minor);
2296 int rc;
Ian Abbott97920072009-02-09 16:51:38 +00002297
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002298 if (!dev) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002299 pr_debug("invalid minor number\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002300 return -ENODEV;
2301 }
2302
David Schleefed9eccb2008-11-04 20:29:31 -08002303 mutex_lock(&dev->mutex);
Eric Parisa8f80e82009-08-13 09:44:51 -04002304 if (!dev->attached && !capable(CAP_NET_ADMIN)) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002305 dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n");
Ian Abbottfc406982013-11-08 15:03:34 +00002306 rc = -ENODEV;
2307 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002308 }
Ian Abbott1363e4f2013-12-11 14:51:03 +00002309 if (dev->attached && dev->use_count == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08002310 if (!try_module_get(dev->driver->module)) {
Ian Abbottfc406982013-11-08 15:03:34 +00002311 rc = -ENOSYS;
2312 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002313 }
Ian Abbott1363e4f2013-12-11 14:51:03 +00002314 if (dev->open) {
2315 rc = dev->open(dev);
2316 if (rc < 0) {
2317 module_put(dev->driver->module);
2318 goto out;
2319 }
Ian Abbott3c17ba072010-05-19 14:10:00 +01002320 }
2321 }
David Schleefed9eccb2008-11-04 20:29:31 -08002322
2323 dev->use_count++;
Ian Abbotte5d670d2013-11-08 15:03:40 +00002324 file->private_data = dev;
Ian Abbottfc406982013-11-08 15:03:34 +00002325 rc = 0;
David Schleefed9eccb2008-11-04 20:29:31 -08002326
Ian Abbottfc406982013-11-08 15:03:34 +00002327out:
David Schleefed9eccb2008-11-04 20:29:31 -08002328 mutex_unlock(&dev->mutex);
Ian Abbottfc406982013-11-08 15:03:34 +00002329 if (rc)
2330 comedi_dev_put(dev);
2331 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -08002332}
2333
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002334static int comedi_fasync(int fd, struct file *file, int on)
2335{
Ian Abbotte5d670d2013-11-08 15:03:40 +00002336 struct comedi_device *dev = file->private_data;
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002337
2338 return fasync_helper(fd, file, on, &dev->async_queue);
2339}
2340
David Schleefed9eccb2008-11-04 20:29:31 -08002341static int comedi_close(struct inode *inode, struct file *file)
2342{
Ian Abbotte5d670d2013-11-08 15:03:40 +00002343 struct comedi_device *dev = file->private_data;
Bill Pemberton34c43922009-03-16 22:05:14 -04002344 struct comedi_subdevice *s = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08002345 int i;
Bernd Porr3ffab422011-11-08 21:23:03 +00002346
David Schleefed9eccb2008-11-04 20:29:31 -08002347 mutex_lock(&dev->mutex);
2348
2349 if (dev->subdevices) {
2350 for (i = 0; i < dev->n_subdevices; i++) {
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07002351 s = &dev->subdevices[i];
David Schleefed9eccb2008-11-04 20:29:31 -08002352
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002353 if (s->busy == file)
David Schleefed9eccb2008-11-04 20:29:31 -08002354 do_cancel(dev, s);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002355 if (s->lock == file)
David Schleefed9eccb2008-11-04 20:29:31 -08002356 s->lock = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08002357 }
2358 }
Ian Abbott1363e4f2013-12-11 14:51:03 +00002359 if (dev->attached && dev->use_count == 1) {
2360 if (dev->close)
2361 dev->close(dev);
David Schleefed9eccb2008-11-04 20:29:31 -08002362 module_put(dev->driver->module);
Ian Abbott1363e4f2013-12-11 14:51:03 +00002363 }
David Schleefed9eccb2008-11-04 20:29:31 -08002364
2365 dev->use_count--;
2366
2367 mutex_unlock(&dev->mutex);
Ian Abbottfc406982013-11-08 15:03:34 +00002368 comedi_dev_put(dev);
David Schleefed9eccb2008-11-04 20:29:31 -08002369
David Schleefed9eccb2008-11-04 20:29:31 -08002370 return 0;
2371}
2372
Ian Abbott8cb8aad2012-06-19 10:17:43 +01002373static const struct file_operations comedi_fops = {
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302374 .owner = THIS_MODULE,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302375 .unlocked_ioctl = comedi_unlocked_ioctl,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302376 .compat_ioctl = comedi_compat_ioctl,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302377 .open = comedi_open,
2378 .release = comedi_close,
2379 .read = comedi_read,
2380 .write = comedi_write,
2381 .mmap = comedi_mmap,
2382 .poll = comedi_poll,
2383 .fasync = comedi_fasync,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002384 .llseek = noop_llseek,
David Schleefed9eccb2008-11-04 20:29:31 -08002385};
2386
Bill Pemberton34c43922009-03-16 22:05:14 -04002387void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002388{
Bill Pembertond1636792009-03-16 22:05:20 -04002389 struct comedi_async *async = s->async;
David Schleefed9eccb2008-11-04 20:29:31 -08002390 unsigned runflags = 0;
2391 unsigned runflags_mask = 0;
2392
H Hartley Sweetenf0124632012-12-19 15:43:18 -07002393 if (!comedi_is_subdevice_running(s))
David Schleefed9eccb2008-11-04 20:29:31 -08002394 return;
2395
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302396 if (s->
2397 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2398 COMEDI_CB_OVERFLOW)) {
David Schleefed9eccb2008-11-04 20:29:31 -08002399 runflags_mask |= SRF_RUNNING;
2400 }
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002401 /* remember if an error event has occurred, so an error
David Schleefed9eccb2008-11-04 20:29:31 -08002402 * can be returned the next time the user does a read() */
2403 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2404 runflags_mask |= SRF_ERROR;
2405 runflags |= SRF_ERROR;
2406 }
2407 if (runflags_mask) {
2408 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2409 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2410 }
2411
2412 if (async->cb_mask & s->async->events) {
Ian Abbottc265be02013-11-08 15:03:22 +00002413 wake_up_interruptible(&async->wait_head);
2414 if (s->subdev_flags & SDF_CMD_READ)
2415 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2416 if (s->subdev_flags & SDF_CMD_WRITE)
2417 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
David Schleefed9eccb2008-11-04 20:29:31 -08002418 }
2419 s->async->events = 0;
2420}
H Hartley Sweeten5660e742013-04-12 10:11:54 -07002421EXPORT_SYMBOL_GPL(comedi_event);
David Schleefed9eccb2008-11-04 20:29:31 -08002422
Ian Abbott07778392013-04-04 14:58:51 +01002423/* Note: the ->mutex is pre-locked on successful return */
Ian Abbott7638ffc2013-04-04 14:58:50 +01002424struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
David Schleefed9eccb2008-11-04 20:29:31 -08002425{
Ian Abbott7638ffc2013-04-04 14:58:50 +01002426 struct comedi_device *dev;
Bill Pemberton0bfbbe82009-03-16 22:05:36 -04002427 struct device *csdev;
David Schleefed9eccb2008-11-04 20:29:31 -08002428 unsigned i;
2429
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07002430 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002431 if (dev == NULL)
Ian Abbott7638ffc2013-04-04 14:58:50 +01002432 return ERR_PTR(-ENOMEM);
Ian Abbott7638ffc2013-04-04 14:58:50 +01002433 comedi_device_init(dev);
Ian Abbottdb2e3482013-04-04 14:59:00 +01002434 comedi_set_hw_dev(dev, hardware_device);
Ian Abbott07778392013-04-04 14:58:51 +01002435 mutex_lock(&dev->mutex);
Ian Abbott5b7dba12013-04-04 14:59:04 +01002436 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbott38b97222013-04-04 14:58:52 +01002437 for (i = hardware_device ? comedi_num_legacy_minors : 0;
2438 i < COMEDI_NUM_BOARD_MINORS; ++i) {
Ian Abbott5b7dba12013-04-04 14:59:04 +01002439 if (comedi_board_minor_table[i] == NULL) {
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002440 comedi_board_minor_table[i] = dev;
David Schleefed9eccb2008-11-04 20:29:31 -08002441 break;
2442 }
2443 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002444 mutex_unlock(&comedi_board_minor_table_lock);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002445 if (i == COMEDI_NUM_BOARD_MINORS) {
Ian Abbott07778392013-04-04 14:58:51 +01002446 mutex_unlock(&dev->mutex);
Ian Abbott7638ffc2013-04-04 14:58:50 +01002447 comedi_device_cleanup(dev);
Ian Abbott5b13ed92013-11-08 15:03:32 +00002448 comedi_dev_put(dev);
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07002449 pr_err("ran out of minor numbers for board device files\n");
Ian Abbott7638ffc2013-04-04 14:58:50 +01002450 return ERR_PTR(-EBUSY);
David Schleefed9eccb2008-11-04 20:29:31 -08002451 }
Ian Abbott7638ffc2013-04-04 14:58:50 +01002452 dev->minor = i;
Pavel Roskin0435f932011-07-06 10:15:44 -04002453 csdev = device_create(comedi_class, hardware_device,
2454 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002455 if (!IS_ERR(csdev))
Ian Abbott8f988d82013-12-11 14:51:02 +00002456 dev->class_dev = get_device(csdev);
H Hartley Sweetena5011a22012-05-09 09:20:08 -07002457
Ian Abbott07778392013-04-04 14:58:51 +01002458 /* Note: dev->mutex needs to be unlocked by the caller. */
Ian Abbott7638ffc2013-04-04 14:58:50 +01002459 return dev;
David Schleefed9eccb2008-11-04 20:29:31 -08002460}
2461
Ian Abbott70f30c32013-04-04 14:58:49 +01002462static void comedi_free_board_minor(unsigned minor)
Ian Abbott24fb1342013-04-04 14:58:46 +01002463{
2464 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002465 comedi_free_board_dev(comedi_clear_board_minor(minor));
Ian Abbott24fb1342013-04-04 14:58:46 +01002466}
2467
Ian Abbott3346b792013-04-04 14:58:47 +01002468void comedi_release_hardware_device(struct device *hardware_device)
Ian Abbottc43435d2012-03-30 17:14:58 +01002469{
2470 int minor;
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002471 struct comedi_device *dev;
Ian Abbottc43435d2012-03-30 17:14:58 +01002472
Ian Abbott38b97222013-04-04 14:58:52 +01002473 for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
2474 minor++) {
Ian Abbott5b7dba12013-04-04 14:59:04 +01002475 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002476 dev = comedi_board_minor_table[minor];
2477 if (dev && dev->hw_dev == hardware_device) {
Ian Abbott5b7dba12013-04-04 14:59:04 +01002478 comedi_board_minor_table[minor] = NULL;
2479 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002480 comedi_free_board_dev(dev);
Ian Abbott3346b792013-04-04 14:58:47 +01002481 break;
Ian Abbottc43435d2012-03-30 17:14:58 +01002482 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002483 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottc43435d2012-03-30 17:14:58 +01002484 }
Ian Abbottc43435d2012-03-30 17:14:58 +01002485}
2486
Ian Abbottf65cc542013-02-01 10:20:30 +00002487int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002488{
Ian Abbottf65cc542013-02-01 10:20:30 +00002489 struct comedi_device *dev = s->device;
Bill Pemberton0bfbbe82009-03-16 22:05:36 -04002490 struct device *csdev;
David Schleefed9eccb2008-11-04 20:29:31 -08002491 unsigned i;
2492
Ian Abbott5b7dba12013-04-04 14:59:04 +01002493 mutex_lock(&comedi_subdevice_minor_table_lock);
2494 for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
2495 if (comedi_subdevice_minor_table[i] == NULL) {
Ian Abbottbd5b4172013-04-04 14:59:15 +01002496 comedi_subdevice_minor_table[i] = s;
David Schleefed9eccb2008-11-04 20:29:31 -08002497 break;
2498 }
2499 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002500 mutex_unlock(&comedi_subdevice_minor_table_lock);
2501 if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07002502 pr_err("ran out of minor numbers for subdevice files\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002503 return -EBUSY;
2504 }
Ian Abbott5b7dba12013-04-04 14:59:04 +01002505 i += COMEDI_NUM_BOARD_MINORS;
David Schleefed9eccb2008-11-04 20:29:31 -08002506 s->minor = i;
Pavel Roskin0435f932011-07-06 10:15:44 -04002507 csdev = device_create(comedi_class, dev->class_dev,
2508 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
H Hartley Sweeten90a35c12012-12-19 17:27:02 -07002509 dev->minor, s->index);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002510 if (!IS_ERR(csdev))
David Schleefed9eccb2008-11-04 20:29:31 -08002511 s->class_dev = csdev;
H Hartley Sweetena5011a22012-05-09 09:20:08 -07002512
Ian Abbottda718542013-02-07 16:03:00 +00002513 return 0;
David Schleefed9eccb2008-11-04 20:29:31 -08002514}
2515
Bill Pemberton34c43922009-03-16 22:05:14 -04002516void comedi_free_subdevice_minor(struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08002517{
Ian Abbott0fcc9d42013-04-04 14:59:13 +01002518 unsigned int i;
David Schleefed9eccb2008-11-04 20:29:31 -08002519
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002520 if (s == NULL)
2521 return;
2522 if (s->minor < 0)
2523 return;
David Schleefed9eccb2008-11-04 20:29:31 -08002524
2525 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
Ian Abbott8907cf62013-04-04 14:59:03 +01002526 BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
David Schleefed9eccb2008-11-04 20:29:31 -08002527
Ian Abbott0fcc9d42013-04-04 14:59:13 +01002528 i = s->minor - COMEDI_NUM_BOARD_MINORS;
2529 mutex_lock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +01002530 if (s == comedi_subdevice_minor_table[i])
2531 comedi_subdevice_minor_table[i] = NULL;
Ian Abbott0fcc9d42013-04-04 14:59:13 +01002532 mutex_unlock(&comedi_subdevice_minor_table_lock);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002533 if (s->class_dev) {
David Schleefed9eccb2008-11-04 20:29:31 -08002534 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2535 s->class_dev = NULL;
2536 }
David Schleefed9eccb2008-11-04 20:29:31 -08002537}
H Hartley Sweetena5787822012-12-19 15:40:59 -07002538
Ian Abbott682b9112013-01-28 17:07:39 +00002539static void comedi_cleanup_board_minors(void)
H Hartley Sweeten76cca892012-12-19 15:41:42 -07002540{
2541 unsigned i;
2542
Ian Abbott682b9112013-01-28 17:07:39 +00002543 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
H Hartley Sweeten76cca892012-12-19 15:41:42 -07002544 comedi_free_board_minor(i);
2545}
2546
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002547static int __init comedi_init(void)
2548{
2549 int i;
2550 int retval;
2551
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07002552 pr_info("version " COMEDI_RELEASE " - http://www.comedi.org\n");
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002553
2554 if (comedi_num_legacy_minors < 0 ||
2555 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07002556 pr_err("invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n",
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002557 COMEDI_NUM_BOARD_MINORS);
2558 return -EINVAL;
2559 }
2560
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002561 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2562 COMEDI_NUM_MINORS, "comedi");
2563 if (retval)
2564 return -EIO;
2565 cdev_init(&comedi_cdev, &comedi_fops);
2566 comedi_cdev.owner = THIS_MODULE;
Anton Protopopova5bde3a2014-07-09 09:12:37 +04002567
2568 retval = kobject_set_name(&comedi_cdev.kobj, "comedi");
2569 if (retval) {
2570 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2571 COMEDI_NUM_MINORS);
2572 return retval;
2573 }
2574
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002575 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2576 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2577 COMEDI_NUM_MINORS);
2578 return -EIO;
2579 }
2580 comedi_class = class_create(THIS_MODULE, "comedi");
2581 if (IS_ERR(comedi_class)) {
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07002582 pr_err("failed to create class\n");
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002583 cdev_del(&comedi_cdev);
2584 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2585 COMEDI_NUM_MINORS);
2586 return PTR_ERR(comedi_class);
2587 }
2588
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -07002589 comedi_class->dev_groups = comedi_dev_groups;
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002590
2591 /* XXX requires /proc interface */
2592 comedi_proc_init();
2593
2594 /* create devices files for legacy/manual use */
2595 for (i = 0; i < comedi_num_legacy_minors; i++) {
Ian Abbott7638ffc2013-04-04 14:58:50 +01002596 struct comedi_device *dev;
Raghavendra Ganiga4bac39f2014-05-01 13:53:12 +05302597
Ian Abbott7638ffc2013-04-04 14:58:50 +01002598 dev = comedi_alloc_board_minor(NULL);
2599 if (IS_ERR(dev)) {
Ian Abbott682b9112013-01-28 17:07:39 +00002600 comedi_cleanup_board_minors();
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002601 cdev_del(&comedi_cdev);
2602 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2603 COMEDI_NUM_MINORS);
Ian Abbott7638ffc2013-04-04 14:58:50 +01002604 return PTR_ERR(dev);
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002605 }
Kinka Huangcb3aada2014-07-15 23:11:02 +08002606 /* comedi_alloc_board_minor() locked the mutex */
2607 mutex_unlock(&dev->mutex);
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002608 }
2609
2610 return 0;
2611}
2612module_init(comedi_init);
2613
2614static void __exit comedi_cleanup(void)
2615{
2616 int i;
2617
Ian Abbott682b9112013-01-28 17:07:39 +00002618 comedi_cleanup_board_minors();
Ian Abbott5b7dba12013-04-04 14:59:04 +01002619 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
2620 BUG_ON(comedi_board_minor_table[i]);
2621 for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
2622 BUG_ON(comedi_subdevice_minor_table[i]);
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07002623
2624 class_destroy(comedi_class);
2625 cdev_del(&comedi_cdev);
2626 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2627
2628 comedi_proc_cleanup();
2629}
2630module_exit(comedi_cleanup);
2631
H Hartley Sweetena5787822012-12-19 15:40:59 -07002632MODULE_AUTHOR("http://www.comedi.org");
2633MODULE_DESCRIPTION("Comedi core module");
2634MODULE_LICENSE("GPL");