blob: 55a0cae04b8d163c01bb19356c7bcf900656aefd [file] [log] [blame]
Greg Kroah-Hartmane184e2b2017-11-07 14:58:43 +01001// SPDX-License-Identifier: GPL-2.0+
David Schleefed9eccb2008-11-04 20:29:31 -08002/*
Ian Abbottf6fef5d2015-01-28 18:41:45 +00003 * comedi/comedi_fops.c
4 * comedi kernel module
5 *
6 * COMEDI - Linux Control and Measurement Device Interface
Al Viroe0d0bf82020-04-25 18:19:30 -04007 * Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org>
8 * compat ioctls:
9 * Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
10 * Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
Ian Abbottf6fef5d2015-01-28 18:41:45 +000011 */
David Schleefed9eccb2008-11-04 20:29:31 -080012
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -070013#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
David Schleefed9eccb2008-11-04 20:29:31 -080015#include <linux/module.h>
16#include <linux/errno.h>
17#include <linux/kernel.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010018#include <linux/sched/signal.h>
David Schleefed9eccb2008-11-04 20:29:31 -080019#include <linux/fcntl.h>
20#include <linux/delay.h>
David Schleefed9eccb2008-11-04 20:29:31 -080021#include <linux/mm.h>
22#include <linux/slab.h>
David Schleefed9eccb2008-11-04 20:29:31 -080023#include <linux/poll.h>
David Schleefed9eccb2008-11-04 20:29:31 -080024#include <linux/device.h>
David Schleefed9eccb2008-11-04 20:29:31 -080025#include <linux/fs.h>
Ian Abbottdf0e68c12021-11-17 12:05:59 +000026#include <linux/comedi/comedidev.h>
David Schleefed9eccb2008-11-04 20:29:31 -080027#include <linux/cdev.h>
28
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -080029#include <linux/io.h>
30#include <linux/uaccess.h>
Al Viroe0d0bf82020-04-25 18:19:30 -040031#include <linux/compat.h>
David Schleefed9eccb2008-11-04 20:29:31 -080032
Ian Abbott3a5fa272012-06-19 10:17:44 +010033#include "comedi_internal.h"
David Schleefed9eccb2008-11-04 20:29:31 -080034
Ian Abbott63107ce2015-09-18 15:46:23 +010035/*
Ian Abbotteb340ac2015-04-21 13:18:11 +010036 * comedi_subdevice "runflags"
Ian Abbott63107ce2015-09-18 15:46:23 +010037 * COMEDI_SRF_RT: DEPRECATED: command is running real-time
38 * COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred
Ian Abbotteb340ac2015-04-21 13:18:11 +010039 * since the last command was started
Ian Abbott63107ce2015-09-18 15:46:23 +010040 * COMEDI_SRF_RUNNING: command is running
41 * COMEDI_SRF_FREE_SPRIV: free s->private on detach
Ian Abbotteb340ac2015-04-21 13:18:11 +010042 *
Ian Abbott63107ce2015-09-18 15:46:23 +010043 * COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy"
Ian Abbotteb340ac2015-04-21 13:18:11 +010044 */
45#define COMEDI_SRF_RT BIT(1)
46#define COMEDI_SRF_ERROR BIT(2)
47#define COMEDI_SRF_RUNNING BIT(27)
48#define COMEDI_SRF_FREE_SPRIV BIT(31)
49
50#define COMEDI_SRF_BUSY_MASK (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING)
51
52/**
Ian Abbotta3e39942015-09-23 16:33:27 +010053 * struct comedi_file - Per-file private data for COMEDI device
54 * @dev: COMEDI device.
55 * @read_subdev: Current "read" subdevice.
56 * @write_subdev: Current "write" subdevice.
57 * @last_detach_count: Last known detach count.
58 * @last_attached: Last known attached/detached state.
Ian Abbott20f083c2014-11-04 18:09:00 +000059 */
60struct comedi_file {
61 struct comedi_device *dev;
62 struct comedi_subdevice *read_subdev;
63 struct comedi_subdevice *write_subdev;
64 unsigned int last_detach_count;
Giulio Benettib3c16222018-06-12 16:50:28 +020065 unsigned int last_attached:1;
Ian Abbott20f083c2014-11-04 18:09:00 +000066};
67
Ian Abbotteda56822013-04-04 14:59:02 +010068#define COMEDI_NUM_MINORS 0x100
Ian Abbott5b7dba1b2013-04-04 14:59:04 +010069#define COMEDI_NUM_SUBDEVICE_MINORS \
70 (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
Ian Abbotteda56822013-04-04 14:59:02 +010071
Cheah Kok Cheongd1d78d22017-03-08 02:13:58 +080072static unsigned short comedi_num_legacy_minors;
73module_param(comedi_num_legacy_minors, ushort, 0444);
Ian Abbott4d7df822012-04-13 14:12:53 +010074MODULE_PARM_DESC(comedi_num_legacy_minors,
75 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
76 );
77
Ian Abbott234bb3c2012-04-13 14:12:54 +010078unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
Matias Mucciolo6e302932016-09-12 10:18:59 -030079module_param(comedi_default_buf_size_kb, uint, 0644);
Ian Abbott4d7df822012-04-13 14:12:53 +010080MODULE_PARM_DESC(comedi_default_buf_size_kb,
81 "default asynchronous buffer size in KiB (default "
Ian Abbott234bb3c2012-04-13 14:12:54 +010082 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
Ian Abbott4d7df822012-04-13 14:12:53 +010083
Nishad Kamdar642e0692018-07-14 21:14:58 +053084unsigned int comedi_default_buf_maxsize_kb =
85 CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
Matias Mucciolo6e302932016-09-12 10:18:59 -030086module_param(comedi_default_buf_maxsize_kb, uint, 0644);
Ian Abbott4d7df822012-04-13 14:12:53 +010087MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
88 "default maximum size of asynchronous buffer in KiB (default "
Ian Abbott234bb3c2012-04-13 14:12:54 +010089 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
Bernd Porr1dd33ab2008-12-08 23:30:13 +000090
Ian Abbott5b7dba1b2013-04-04 14:59:04 +010091static DEFINE_MUTEX(comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +010092static struct comedi_device
Ian Abbott5b7dba1b2013-04-04 14:59:04 +010093*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
94
95static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
96/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
Ian Abbottbd5b4172013-04-04 14:59:15 +010097static struct comedi_subdevice
Ian Abbott5b7dba1b2013-04-04 14:59:04 +010098*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
David Schleefed9eccb2008-11-04 20:29:31 -080099
Ian Abbottd9740a02013-04-04 14:58:55 +0100100static struct class *comedi_class;
101static struct cdev comedi_cdev;
102
103static void comedi_device_init(struct comedi_device *dev)
104{
Ian Abbott5b13ed92013-11-08 15:03:32 +0000105 kref_init(&dev->refcount);
Ian Abbottd9740a02013-04-04 14:58:55 +0100106 spin_lock_init(&dev->spinlock);
107 mutex_init(&dev->mutex);
Ian Abbott2f3fdcd2013-11-08 15:03:24 +0000108 init_rwsem(&dev->attach_lock);
Ian Abbottd9740a02013-04-04 14:58:55 +0100109 dev->minor = -1;
110}
111
Ian Abbott5b13ed92013-11-08 15:03:32 +0000112static void comedi_dev_kref_release(struct kref *kref)
113{
114 struct comedi_device *dev =
115 container_of(kref, struct comedi_device, refcount);
116
117 mutex_destroy(&dev->mutex);
Ian Abbott8f988d82013-12-11 14:51:02 +0000118 put_device(dev->class_dev);
Ian Abbott5b13ed92013-11-08 15:03:32 +0000119 kfree(dev);
120}
121
Ian Abbottdd630cd2015-01-28 18:41:46 +0000122/**
Ian Abbotta3e39942015-09-23 16:33:27 +0100123 * comedi_dev_put() - Release a use of a COMEDI device
124 * @dev: COMEDI device.
Ian Abbottdd630cd2015-01-28 18:41:46 +0000125 *
Ian Abbotta3e39942015-09-23 16:33:27 +0100126 * Must be called when a user of a COMEDI device is finished with it.
127 * When the last user of the COMEDI device calls this function, the
128 * COMEDI device is destroyed.
Ian Abbottdd630cd2015-01-28 18:41:46 +0000129 *
Ian Abbotta3e39942015-09-23 16:33:27 +0100130 * Return: 1 if the COMEDI device is destroyed by this call or @dev is
131 * NULL, otherwise return 0. Callers must not assume the COMEDI
Ian Abbottdd630cd2015-01-28 18:41:46 +0000132 * device is still valid if this function returns 0.
133 */
Ian Abbott5b13ed92013-11-08 15:03:32 +0000134int comedi_dev_put(struct comedi_device *dev)
135{
136 if (dev)
137 return kref_put(&dev->refcount, comedi_dev_kref_release);
138 return 1;
139}
Ian Abbottb449c1c2013-11-08 15:03:33 +0000140EXPORT_SYMBOL_GPL(comedi_dev_put);
141
142static struct comedi_device *comedi_dev_get(struct comedi_device *dev)
143{
144 if (dev)
145 kref_get(&dev->refcount);
146 return dev;
147}
Ian Abbott5b13ed92013-11-08 15:03:32 +0000148
Ian Abbottd9740a02013-04-04 14:58:55 +0100149static void comedi_device_cleanup(struct comedi_device *dev)
150{
151 struct module *driver_module = NULL;
152
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -0700153 if (!dev)
Ian Abbottd9740a02013-04-04 14:58:55 +0100154 return;
155 mutex_lock(&dev->mutex);
156 if (dev->attached)
157 driver_module = dev->driver->module;
158 comedi_device_detach(dev);
Ian Abbott1363e4f2013-12-11 14:51:03 +0000159 if (driver_module && dev->use_count)
160 module_put(driver_module);
Ian Abbottd9740a02013-04-04 14:58:55 +0100161 mutex_unlock(&dev->mutex);
Ian Abbottd9740a02013-04-04 14:58:55 +0100162}
163
Ian Abbottdb210da2013-04-04 14:59:18 +0100164static bool comedi_clear_board_dev(struct comedi_device *dev)
165{
166 unsigned int i = dev->minor;
167 bool cleared = false;
168
Ian Abbott77c21b62019-04-17 15:39:29 +0100169 lockdep_assert_held(&dev->mutex);
Ian Abbottdb210da2013-04-04 14:59:18 +0100170 mutex_lock(&comedi_board_minor_table_lock);
171 if (dev == comedi_board_minor_table[i]) {
172 comedi_board_minor_table[i] = NULL;
173 cleared = true;
174 }
175 mutex_unlock(&comedi_board_minor_table_lock);
176 return cleared;
177}
178
Leslie Kleind4d47892016-03-21 09:18:35 -0400179static struct comedi_device *comedi_clear_board_minor(unsigned int minor)
Ian Abbottd9740a02013-04-04 14:58:55 +0100180{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100181 struct comedi_device *dev;
Ian Abbottd9740a02013-04-04 14:58:55 +0100182
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100183 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100184 dev = comedi_board_minor_table[minor];
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100185 comedi_board_minor_table[minor] = NULL;
186 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100187 return dev;
Ian Abbottd9740a02013-04-04 14:58:55 +0100188}
189
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100190static void comedi_free_board_dev(struct comedi_device *dev)
Ian Abbottd9740a02013-04-04 14:58:55 +0100191{
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100192 if (dev) {
Ian Abbott52ef9e72014-01-07 12:38:32 +0000193 comedi_device_cleanup(dev);
Ian Abbottcb6b79d2013-04-04 14:59:16 +0100194 if (dev->class_dev) {
195 device_destroy(comedi_class,
196 MKDEV(COMEDI_MAJOR, dev->minor));
Ian Abbottd9740a02013-04-04 14:58:55 +0100197 }
Ian Abbott5b13ed92013-11-08 15:03:32 +0000198 comedi_dev_put(dev);
Ian Abbottd9740a02013-04-04 14:58:55 +0100199 }
200}
Ian Abbott8ab4ed62013-04-04 14:58:54 +0100201
Ian Abbottb2073dc2016-03-29 10:49:04 +0100202static struct comedi_subdevice *
203comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned int minor)
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100204{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100205 struct comedi_subdevice *s;
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100206 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
207
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100208 mutex_lock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +0100209 s = comedi_subdevice_minor_table[i];
Ian Abbott63ab0392013-11-08 15:03:42 +0000210 if (s && s->device != dev)
211 s = NULL;
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100212 mutex_unlock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +0100213 return s;
Ian Abbott5b7dba1b2013-04-04 14:59:04 +0100214}
215
Leslie Kleind4d47892016-03-21 09:18:35 -0400216static struct comedi_device *comedi_dev_get_from_board_minor(unsigned int minor)
Ian Abbottb449c1c2013-11-08 15:03:33 +0000217{
218 struct comedi_device *dev;
219
Ian Abbottb449c1c2013-11-08 15:03:33 +0000220 mutex_lock(&comedi_board_minor_table_lock);
221 dev = comedi_dev_get(comedi_board_minor_table[minor]);
222 mutex_unlock(&comedi_board_minor_table_lock);
223 return dev;
224}
225
Ian Abbottb2073dc2016-03-29 10:49:04 +0100226static struct comedi_device *
227comedi_dev_get_from_subdevice_minor(unsigned int minor)
Ian Abbottb449c1c2013-11-08 15:03:33 +0000228{
229 struct comedi_device *dev;
230 struct comedi_subdevice *s;
231 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
232
Ian Abbottb449c1c2013-11-08 15:03:33 +0000233 mutex_lock(&comedi_subdevice_minor_table_lock);
234 s = comedi_subdevice_minor_table[i];
235 dev = comedi_dev_get(s ? s->device : NULL);
236 mutex_unlock(&comedi_subdevice_minor_table_lock);
237 return dev;
238}
239
Ian Abbottdd630cd2015-01-28 18:41:46 +0000240/**
Ian Abbotta3e39942015-09-23 16:33:27 +0100241 * comedi_dev_get_from_minor() - Get COMEDI device by minor device number
242 * @minor: Minor device number.
Ian Abbottdd630cd2015-01-28 18:41:46 +0000243 *
Ian Abbotta3e39942015-09-23 16:33:27 +0100244 * Finds the COMEDI device associated with the minor device number, if any,
245 * and increments its reference count. The COMEDI device is prevented from
Ian Abbottdd630cd2015-01-28 18:41:46 +0000246 * being freed until a matching call is made to comedi_dev_put().
247 *
Ian Abbotta3e39942015-09-23 16:33:27 +0100248 * Return: A pointer to the COMEDI device if it exists, with its usage
249 * reference incremented. Return NULL if no COMEDI device exists with the
Ian Abbottdd630cd2015-01-28 18:41:46 +0000250 * specified minor device number.
251 */
Leslie Kleind4d47892016-03-21 09:18:35 -0400252struct comedi_device *comedi_dev_get_from_minor(unsigned int minor)
Ian Abbottb449c1c2013-11-08 15:03:33 +0000253{
254 if (minor < COMEDI_NUM_BOARD_MINORS)
255 return comedi_dev_get_from_board_minor(minor);
Kinka Huangcb3aada2014-07-15 23:11:02 +0800256
257 return comedi_dev_get_from_subdevice_minor(minor);
Ian Abbottb449c1c2013-11-08 15:03:33 +0000258}
259EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor);
260
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700261static struct comedi_subdevice *
Ian Abbottda56fdc2013-04-04 14:59:10 +0100262comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700263{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100264 struct comedi_subdevice *s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100265
Ian Abbott77c21b62019-04-17 15:39:29 +0100266 lockdep_assert_held(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100267 if (minor >= COMEDI_NUM_BOARD_MINORS) {
Ian Abbott63ab0392013-11-08 15:03:42 +0000268 s = comedi_subdevice_from_minor(dev, minor);
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -0700269 if (!s || (s->subdev_flags & SDF_CMD_READ))
Ian Abbottbd5b4172013-04-04 14:59:15 +0100270 return s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100271 }
272 return dev->read_subdev;
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700273}
274
275static struct comedi_subdevice *
Ian Abbottda56fdc2013-04-04 14:59:10 +0100276comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700277{
Ian Abbottbd5b4172013-04-04 14:59:15 +0100278 struct comedi_subdevice *s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100279
Ian Abbott77c21b62019-04-17 15:39:29 +0100280 lockdep_assert_held(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100281 if (minor >= COMEDI_NUM_BOARD_MINORS) {
Ian Abbott63ab0392013-11-08 15:03:42 +0000282 s = comedi_subdevice_from_minor(dev, minor);
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -0700283 if (!s || (s->subdev_flags & SDF_CMD_WRITE))
Ian Abbottbd5b4172013-04-04 14:59:15 +0100284 return s;
Ian Abbottda56fdc2013-04-04 14:59:10 +0100285 }
286 return dev->write_subdev;
H Hartley Sweeten43bd33f2012-12-19 15:33:29 -0700287}
288
Ian Abbott20f083c2014-11-04 18:09:00 +0000289static void comedi_file_reset(struct file *file)
290{
291 struct comedi_file *cfp = file->private_data;
292 struct comedi_device *dev = cfp->dev;
293 struct comedi_subdevice *s, *read_s, *write_s;
294 unsigned int minor = iminor(file_inode(file));
295
296 read_s = dev->read_subdev;
297 write_s = dev->write_subdev;
298 if (minor >= COMEDI_NUM_BOARD_MINORS) {
299 s = comedi_subdevice_from_minor(dev, minor);
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -0700300 if (!s || s->subdev_flags & SDF_CMD_READ)
Ian Abbott20f083c2014-11-04 18:09:00 +0000301 read_s = s;
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -0700302 if (!s || s->subdev_flags & SDF_CMD_WRITE)
Ian Abbott20f083c2014-11-04 18:09:00 +0000303 write_s = s;
304 }
305 cfp->last_attached = dev->attached;
306 cfp->last_detach_count = dev->detach_count;
Shyam Saini34d34732016-05-10 21:21:07 +0530307 WRITE_ONCE(cfp->read_subdev, read_s);
308 WRITE_ONCE(cfp->write_subdev, write_s);
Ian Abbott20f083c2014-11-04 18:09:00 +0000309}
310
311static void comedi_file_check(struct file *file)
312{
313 struct comedi_file *cfp = file->private_data;
314 struct comedi_device *dev = cfp->dev;
315
316 if (cfp->last_attached != dev->attached ||
317 cfp->last_detach_count != dev->detach_count)
318 comedi_file_reset(file);
319}
320
321static struct comedi_subdevice *comedi_file_read_subdevice(struct file *file)
322{
323 struct comedi_file *cfp = file->private_data;
324
325 comedi_file_check(file);
Shyam Saini34d34732016-05-10 21:21:07 +0530326 return READ_ONCE(cfp->read_subdev);
Ian Abbott20f083c2014-11-04 18:09:00 +0000327}
328
329static struct comedi_subdevice *comedi_file_write_subdevice(struct file *file)
330{
331 struct comedi_file *cfp = file->private_data;
332
333 comedi_file_check(file);
Shyam Saini34d34732016-05-10 21:21:07 +0530334 return READ_ONCE(cfp->write_subdev);
Ian Abbott20f083c2014-11-04 18:09:00 +0000335}
336
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400337static int resize_async_buffer(struct comedi_device *dev,
Ian Abbottb2073dc2016-03-29 10:49:04 +0100338 struct comedi_subdevice *s,
339 unsigned int new_size)
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700340{
Ian Abbott482f0a22014-05-02 13:50:14 +0100341 struct comedi_async *async = s->async;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700342 int retval;
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400343
Ian Abbott77c21b62019-04-17 15:39:29 +0100344 lockdep_assert_held(&dev->mutex);
345
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700346 if (new_size > async->max_bufsize)
347 return -EPERM;
348
349 if (s->busy) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700350 dev_dbg(dev->class_dev,
351 "subdevice is busy, cannot resize buffer\n");
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700352 return -EBUSY;
353 }
Ian Abbottd4526ab2014-05-06 13:12:11 +0100354 if (comedi_buf_is_mmapped(s)) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700355 dev_dbg(dev->class_dev,
356 "subdevice is mmapped, cannot resize buffer\n");
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700357 return -EBUSY;
358 }
359
Ian Abbotta2aab8b2015-01-28 18:41:50 +0000360 /* make sure buffer is an integral number of pages (we round up) */
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700361 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
362
363 retval = comedi_buf_alloc(dev, s, new_size);
364 if (retval < 0)
365 return retval;
366
367 if (s->buf_change) {
H Hartley Sweetend546b892014-07-21 11:48:32 -0700368 retval = s->buf_change(dev, s);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700369 if (retval < 0)
370 return retval;
371 }
372
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700373 dev_dbg(dev->class_dev, "subd %d buffer resized to %i bytes\n",
374 s->index, async->prealloc_bufsz);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700375 return 0;
376}
377
378/* sysfs attribute files */
379
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700380static ssize_t max_read_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700381 struct device_attribute *attr, char *buf)
382{
Ian Abbottc88db462013-04-04 14:59:09 +0100383 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100384 struct comedi_device *dev;
385 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700386 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700387
Ian Abbottbe535c92013-11-08 15:03:37 +0000388 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100389 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100390 return -ENODEV;
391
Ian Abbott7f4656c2013-04-04 14:59:08 +0100392 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100393 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700394 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
395 size = s->async->max_bufsize / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100396 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700397
Ian Abbottbe535c92013-11-08 15:03:37 +0000398 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600399 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700400}
401
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700402static ssize_t max_read_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700403 struct device_attribute *attr,
404 const char *buf, size_t count)
405{
Ian Abbottc88db462013-04-04 14:59:09 +0100406 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100407 struct comedi_device *dev;
408 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700409 unsigned int size;
410 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700411
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700412 err = kstrtouint(buf, 10, &size);
413 if (err)
414 return err;
415 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700416 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700417 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700418
Ian Abbottbe535c92013-11-08 15:03:37 +0000419 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100420 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100421 return -ENODEV;
422
Ian Abbott7f4656c2013-04-04 14:59:08 +0100423 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100424 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700425 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
426 s->async->max_bufsize = size;
427 else
428 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100429 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700430
Ian Abbottbe535c92013-11-08 15:03:37 +0000431 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700432 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700433}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700434static DEVICE_ATTR_RW(max_read_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700435
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700436static ssize_t read_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700437 struct device_attribute *attr, char *buf)
438{
Ian Abbottc88db462013-04-04 14:59:09 +0100439 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100440 struct comedi_device *dev;
441 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700442 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700443
Ian Abbottbe535c92013-11-08 15:03:37 +0000444 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100445 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100446 return -ENODEV;
447
Ian Abbott7f4656c2013-04-04 14:59:08 +0100448 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100449 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700450 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
451 size = s->async->prealloc_bufsz / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100452 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700453
Ian Abbottbe535c92013-11-08 15:03:37 +0000454 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600455 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700456}
457
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700458static ssize_t read_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700459 struct device_attribute *attr,
460 const char *buf, size_t count)
461{
Ian Abbottc88db462013-04-04 14:59:09 +0100462 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100463 struct comedi_device *dev;
464 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700465 unsigned int size;
466 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700467
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700468 err = kstrtouint(buf, 10, &size);
469 if (err)
470 return err;
471 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700472 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700473 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700474
Ian Abbottbe535c92013-11-08 15:03:37 +0000475 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100476 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100477 return -ENODEV;
478
Ian Abbott7f4656c2013-04-04 14:59:08 +0100479 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100480 s = comedi_read_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700481 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
Ian Abbott482f0a22014-05-02 13:50:14 +0100482 err = resize_async_buffer(dev, s, size);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700483 else
484 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100485 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700486
Ian Abbottbe535c92013-11-08 15:03:37 +0000487 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700488 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700489}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700490static DEVICE_ATTR_RW(read_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700491
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700492static ssize_t max_write_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700493 struct device_attribute *attr,
494 char *buf)
495{
Ian Abbottc88db462013-04-04 14:59:09 +0100496 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100497 struct comedi_device *dev;
498 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700499 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700500
Ian Abbottbe535c92013-11-08 15:03:37 +0000501 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100502 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100503 return -ENODEV;
504
Ian Abbott7f4656c2013-04-04 14:59:08 +0100505 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100506 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700507 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
508 size = s->async->max_bufsize / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100509 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700510
Ian Abbottbe535c92013-11-08 15:03:37 +0000511 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600512 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700513}
514
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700515static ssize_t max_write_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700516 struct device_attribute *attr,
517 const char *buf, size_t count)
518{
Ian Abbottc88db462013-04-04 14:59:09 +0100519 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100520 struct comedi_device *dev;
521 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700522 unsigned int size;
523 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700524
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700525 err = kstrtouint(buf, 10, &size);
526 if (err)
527 return err;
528 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700529 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700530 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700531
Ian Abbottbe535c92013-11-08 15:03:37 +0000532 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100533 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100534 return -ENODEV;
535
Ian Abbott7f4656c2013-04-04 14:59:08 +0100536 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100537 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700538 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
539 s->async->max_bufsize = size;
540 else
541 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100542 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700543
Ian Abbottbe535c92013-11-08 15:03:37 +0000544 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700545 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700546}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700547static DEVICE_ATTR_RW(max_write_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700548
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700549static ssize_t write_buffer_kb_show(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700550 struct device_attribute *attr, char *buf)
551{
Ian Abbottc88db462013-04-04 14:59:09 +0100552 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100553 struct comedi_device *dev;
554 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700555 unsigned int size = 0;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700556
Ian Abbottbe535c92013-11-08 15:03:37 +0000557 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100558 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100559 return -ENODEV;
560
Ian Abbott7f4656c2013-04-04 14:59:08 +0100561 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100562 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700563 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
564 size = s->async->prealloc_bufsz / 1024;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100565 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700566
Ian Abbottbe535c92013-11-08 15:03:37 +0000567 comedi_dev_put(dev);
Chase Southwoodecd56ff2014-02-12 02:28:35 -0600568 return snprintf(buf, PAGE_SIZE, "%u\n", size);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700569}
570
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700571static ssize_t write_buffer_kb_store(struct device *csdev,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700572 struct device_attribute *attr,
573 const char *buf, size_t count)
574{
Ian Abbottc88db462013-04-04 14:59:09 +0100575 unsigned int minor = MINOR(csdev->devt);
Ian Abbott7f4656c2013-04-04 14:59:08 +0100576 struct comedi_device *dev;
577 struct comedi_subdevice *s;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700578 unsigned int size;
579 int err;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700580
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700581 err = kstrtouint(buf, 10, &size);
582 if (err)
583 return err;
584 if (size > (UINT_MAX / 1024))
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700585 return -EINVAL;
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700586 size *= 1024;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700587
Ian Abbottbe535c92013-11-08 15:03:37 +0000588 dev = comedi_dev_get_from_minor(minor);
Ian Abbott5e04c252013-04-04 14:59:11 +0100589 if (!dev)
Ian Abbottc88db462013-04-04 14:59:09 +0100590 return -ENODEV;
591
Ian Abbott7f4656c2013-04-04 14:59:08 +0100592 mutex_lock(&dev->mutex);
Ian Abbottda56fdc2013-04-04 14:59:10 +0100593 s = comedi_write_subdevice(dev, minor);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700594 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
Ian Abbott482f0a22014-05-02 13:50:14 +0100595 err = resize_async_buffer(dev, s, size);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700596 else
597 err = -EINVAL;
Ian Abbott7f4656c2013-04-04 14:59:08 +0100598 mutex_unlock(&dev->mutex);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700599
Ian Abbottbe535c92013-11-08 15:03:37 +0000600 comedi_dev_put(dev);
H Hartley Sweeten72fd9fa2012-06-05 10:18:02 -0700601 return err ? err : count;
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700602}
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700603static DEVICE_ATTR_RW(write_buffer_kb);
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700604
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700605static struct attribute *comedi_dev_attrs[] = {
606 &dev_attr_max_read_buffer_kb.attr,
607 &dev_attr_read_buffer_kb.attr,
608 &dev_attr_max_write_buffer_kb.attr,
609 &dev_attr_write_buffer_kb.attr,
610 NULL,
H Hartley Sweetena5011a22012-05-09 09:20:08 -0700611};
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -0700612ATTRIBUTE_GROUPS(comedi_dev);
David Schleefed9eccb2008-11-04 20:29:31 -0800613
Ian Abbottef4b4b22015-03-27 15:13:06 +0000614static void __comedi_clear_subdevice_runflags(struct comedi_subdevice *s,
Leslie Kleind4d47892016-03-21 09:18:35 -0400615 unsigned int bits)
Ian Abbottef4b4b22015-03-27 15:13:06 +0000616{
617 s->runflags &= ~bits;
618}
619
620static void __comedi_set_subdevice_runflags(struct comedi_subdevice *s,
Leslie Kleind4d47892016-03-21 09:18:35 -0400621 unsigned int bits)
Ian Abbottef4b4b22015-03-27 15:13:06 +0000622{
623 s->runflags |= bits;
624}
625
Ian Abbottcc64ea42015-03-27 15:13:00 +0000626static void comedi_update_subdevice_runflags(struct comedi_subdevice *s,
Ian Abbottb2073dc2016-03-29 10:49:04 +0100627 unsigned int mask,
628 unsigned int bits)
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700629{
630 unsigned long flags;
631
632 spin_lock_irqsave(&s->spin_lock, flags);
Ian Abbottef4b4b22015-03-27 15:13:06 +0000633 __comedi_clear_subdevice_runflags(s, mask);
634 __comedi_set_subdevice_runflags(s, bits & mask);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700635 spin_unlock_irqrestore(&s->spin_lock, flags);
636}
637
Leslie Kleind4d47892016-03-21 09:18:35 -0400638static unsigned int __comedi_get_subdevice_runflags(struct comedi_subdevice *s)
Ian Abbottef4b4b22015-03-27 15:13:06 +0000639{
640 return s->runflags;
641}
642
Leslie Kleind4d47892016-03-21 09:18:35 -0400643static unsigned int comedi_get_subdevice_runflags(struct comedi_subdevice *s)
H Hartley Sweeten74120712012-12-19 15:42:26 -0700644{
645 unsigned long flags;
Leslie Kleind4d47892016-03-21 09:18:35 -0400646 unsigned int runflags;
H Hartley Sweeten74120712012-12-19 15:42:26 -0700647
648 spin_lock_irqsave(&s->spin_lock, flags);
Ian Abbottef4b4b22015-03-27 15:13:06 +0000649 runflags = __comedi_get_subdevice_runflags(s);
H Hartley Sweeten74120712012-12-19 15:42:26 -0700650 spin_unlock_irqrestore(&s->spin_lock, flags);
651 return runflags;
652}
H Hartley Sweeten74120712012-12-19 15:42:26 -0700653
Leslie Kleind4d47892016-03-21 09:18:35 -0400654static bool comedi_is_runflags_running(unsigned int runflags)
Ian Abbottb183a832015-03-27 15:13:01 +0000655{
656 return runflags & COMEDI_SRF_RUNNING;
657}
658
Leslie Kleind4d47892016-03-21 09:18:35 -0400659static bool comedi_is_runflags_in_error(unsigned int runflags)
Ian Abbottb183a832015-03-27 15:13:01 +0000660{
661 return runflags & COMEDI_SRF_ERROR;
662}
663
Ian Abbottdd630cd2015-01-28 18:41:46 +0000664/**
Ian Abbotta3e39942015-09-23 16:33:27 +0100665 * comedi_is_subdevice_running() - Check if async command running on subdevice
666 * @s: COMEDI subdevice.
Ian Abbottdd630cd2015-01-28 18:41:46 +0000667 *
Ian Abbotta3e39942015-09-23 16:33:27 +0100668 * Return: %true if an asynchronous COMEDI command is active on the
669 * subdevice, else %false.
Ian Abbottdd630cd2015-01-28 18:41:46 +0000670 */
H Hartley Sweetene0dac312012-12-19 15:42:47 -0700671bool comedi_is_subdevice_running(struct comedi_subdevice *s)
672{
Leslie Kleind4d47892016-03-21 09:18:35 -0400673 unsigned int runflags = comedi_get_subdevice_runflags(s);
H Hartley Sweetene0dac312012-12-19 15:42:47 -0700674
Ian Abbottb183a832015-03-27 15:13:01 +0000675 return comedi_is_runflags_running(runflags);
H Hartley Sweetene0dac312012-12-19 15:42:47 -0700676}
677EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
678
Ian Abbottef4b4b22015-03-27 15:13:06 +0000679static bool __comedi_is_subdevice_running(struct comedi_subdevice *s)
680{
Leslie Kleind4d47892016-03-21 09:18:35 -0400681 unsigned int runflags = __comedi_get_subdevice_runflags(s);
Ian Abbottef4b4b22015-03-27 15:13:06 +0000682
683 return comedi_is_runflags_running(runflags);
684}
685
Ian Abbott8fc369a2015-04-21 13:18:10 +0100686bool comedi_can_auto_free_spriv(struct comedi_subdevice *s)
687{
Leslie Kleind4d47892016-03-21 09:18:35 -0400688 unsigned int runflags = __comedi_get_subdevice_runflags(s);
Ian Abbott8fc369a2015-04-21 13:18:10 +0100689
690 return runflags & COMEDI_SRF_FREE_SPRIV;
691}
692
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700693/**
Ian Abbotta3e39942015-09-23 16:33:27 +0100694 * comedi_set_spriv_auto_free() - Mark subdevice private data as freeable
695 * @s: COMEDI subdevice.
Ian Abbott8fc369a2015-04-21 13:18:10 +0100696 *
697 * Mark the subdevice as having a pointer to private data that can be
Ian Abbotta3e39942015-09-23 16:33:27 +0100698 * automatically freed when the COMEDI device is detached from the low-level
699 * driver.
Ian Abbott8fc369a2015-04-21 13:18:10 +0100700 */
701void comedi_set_spriv_auto_free(struct comedi_subdevice *s)
702{
703 __comedi_set_subdevice_runflags(s, COMEDI_SRF_FREE_SPRIV);
704}
705EXPORT_SYMBOL_GPL(comedi_set_spriv_auto_free);
706
707/**
Ian Abbotta3e39942015-09-23 16:33:27 +0100708 * comedi_alloc_spriv - Allocate memory for the subdevice private data
709 * @s: COMEDI subdevice.
710 * @size: Size of the memory to allocate.
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700711 *
Ian Abbotta3e39942015-09-23 16:33:27 +0100712 * Allocate memory for the subdevice private data and point @s->private
713 * to it. The memory will be freed automatically when the COMEDI device
714 * is detached from the low-level driver.
715 *
716 * Return: A pointer to the allocated memory @s->private on success.
717 * Return NULL on failure.
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700718 */
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700719void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700720{
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700721 s->private = kzalloc(size, GFP_KERNEL);
722 if (s->private)
Ian Abbott8fc369a2015-04-21 13:18:10 +0100723 comedi_set_spriv_auto_free(s);
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700724 return s->private;
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700725}
H Hartley Sweeten0480bcb2013-06-19 15:24:36 -0700726EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
H Hartley Sweeten588ba6d2013-06-11 11:32:29 -0700727
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700728/*
Ian Abbotta2aab8b2015-01-28 18:41:50 +0000729 * This function restores a subdevice to an idle state.
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700730 */
731static void do_become_nonbusy(struct comedi_device *dev,
732 struct comedi_subdevice *s)
733{
734 struct comedi_async *async = s->async;
735
Ian Abbott77c21b62019-04-17 15:39:29 +0100736 lockdep_assert_held(&dev->mutex);
Ian Abbottcc64ea42015-03-27 15:13:00 +0000737 comedi_update_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700738 if (async) {
Ian Abbottfcc18a92014-05-06 13:12:10 +0100739 comedi_buf_reset(s);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700740 async->inttrig = NULL;
741 kfree(async->cmd.chanlist);
742 async->cmd.chanlist = NULL;
Ian Abbott8da8c862013-11-08 15:03:27 +0000743 s->busy = NULL;
Ian Abbott258c1dd2015-03-27 15:13:03 +0000744 wake_up_interruptible_all(&async->wait_head);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700745 } else {
746 dev_err(dev->class_dev,
Bryan Garzae4f857f2017-08-23 22:37:00 +0000747 "BUG: (?) %s called with async=NULL\n", __func__);
Ian Abbott8da8c862013-11-08 15:03:27 +0000748 s->busy = NULL;
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700749 }
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700750}
751
752static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
753{
754 int ret = 0;
755
Ian Abbott77c21b62019-04-17 15:39:29 +0100756 lockdep_assert_held(&dev->mutex);
H Hartley Sweetenf0124632012-12-19 15:43:18 -0700757 if (comedi_is_subdevice_running(s) && s->cancel)
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700758 ret = s->cancel(dev, s);
759
760 do_become_nonbusy(dev, s);
761
762 return ret;
763}
764
Ian Abbottd19db512013-11-08 15:03:28 +0000765void comedi_device_cancel_all(struct comedi_device *dev)
766{
767 struct comedi_subdevice *s;
768 int i;
769
Ian Abbott77c21b62019-04-17 15:39:29 +0100770 lockdep_assert_held(&dev->mutex);
Ian Abbottd19db512013-11-08 15:03:28 +0000771 if (!dev->attached)
772 return;
773
774 for (i = 0; i < dev->n_subdevices; i++) {
775 s = &dev->subdevices[i];
776 if (s->async)
777 do_cancel(dev, s);
778 }
779}
780
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700781static int is_device_busy(struct comedi_device *dev)
782{
783 struct comedi_subdevice *s;
784 int i;
785
Ian Abbott77c21b62019-04-17 15:39:29 +0100786 lockdep_assert_held(&dev->mutex);
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700787 if (!dev->attached)
788 return 0;
789
790 for (i = 0; i < dev->n_subdevices; i++) {
791 s = &dev->subdevices[i];
792 if (s->busy)
793 return 1;
Ian Abbottd4526ab2014-05-06 13:12:11 +0100794 if (s->async && comedi_buf_is_mmapped(s))
H Hartley Sweeten2aae0072012-12-19 15:31:57 -0700795 return 1;
796 }
797
798 return 0;
799}
800
David Schleefed9eccb2008-11-04 20:29:31 -0800801/*
Ian Abbott18e01b22015-01-28 18:41:47 +0000802 * COMEDI_DEVCONFIG ioctl
803 * attaches (and configures) or detaches a legacy device
804 *
805 * arg:
806 * pointer to comedi_devconfig structure (NULL if detaching)
807 *
808 * reads:
809 * comedi_devconfig structure (if attaching)
810 *
811 * writes:
812 * nothing
813 */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530814static int do_devconfig_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700815 struct comedi_devconfig __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800816{
Bill Pemberton0707bb02009-03-16 22:06:20 -0400817 struct comedi_devconfig it;
David Schleefed9eccb2008-11-04 20:29:31 -0800818
Ian Abbott77c21b62019-04-17 15:39:29 +0100819 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -0800820 if (!capable(CAP_SYS_ADMIN))
821 return -EPERM;
822
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -0700823 if (!arg) {
David Schleefed9eccb2008-11-04 20:29:31 -0800824 if (is_device_busy(dev))
825 return -EBUSY;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800826 if (dev->attached) {
David Schleefed9eccb2008-11-04 20:29:31 -0800827 struct module *driver_module = dev->driver->module;
Raghavendra Ganiga4bac39f2014-05-01 13:53:12 +0530828
David Schleefed9eccb2008-11-04 20:29:31 -0800829 comedi_device_detach(dev);
830 module_put(driver_module);
831 }
832 return 0;
833 }
834
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700835 if (copy_from_user(&it, arg, sizeof(it)))
David Schleefed9eccb2008-11-04 20:29:31 -0800836 return -EFAULT;
837
838 it.board_name[COMEDI_NAMELEN - 1] = 0;
839
H Hartley Sweetend1843132013-01-09 09:46:10 -0700840 if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
841 dev_warn(dev->class_dev,
842 "comedi_config --init_data is deprecated\n");
843 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -0800844 }
845
Ian Abbott8ab4ed62013-04-04 14:58:54 +0100846 if (dev->minor >= comedi_num_legacy_minors)
847 /* don't re-use dynamically allocated comedi devices */
848 return -EBUSY;
849
Ian Abbottb2a644b2013-04-04 14:58:56 +0100850 /* This increments the driver module count on success. */
851 return comedi_device_attach(dev, &it);
David Schleefed9eccb2008-11-04 20:29:31 -0800852}
853
854/*
Ian Abbott18e01b22015-01-28 18:41:47 +0000855 * COMEDI_BUFCONFIG ioctl
856 * buffer configuration
857 *
858 * arg:
859 * pointer to comedi_bufconfig structure
860 *
861 * reads:
862 * comedi_bufconfig structure
863 *
864 * writes:
865 * modified comedi_bufconfig structure
866 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700867static int do_bufconfig_ioctl(struct comedi_device *dev,
868 struct comedi_bufconfig __user *arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800869{
Bill Pembertonbe6aba42009-03-16 22:06:37 -0400870 struct comedi_bufconfig bc;
Bill Pembertond1636792009-03-16 22:05:20 -0400871 struct comedi_async *async;
Bill Pemberton34c43922009-03-16 22:05:14 -0400872 struct comedi_subdevice *s;
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400873 int retval = 0;
David Schleefed9eccb2008-11-04 20:29:31 -0800874
Ian Abbott77c21b62019-04-17 15:39:29 +0100875 lockdep_assert_held(&dev->mutex);
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700876 if (copy_from_user(&bc, arg, sizeof(bc)))
David Schleefed9eccb2008-11-04 20:29:31 -0800877 return -EFAULT;
878
Güngör Erseymen11f80dd2013-06-07 21:29:49 +0300879 if (bc.subdevice >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -0800880 return -EINVAL;
881
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700882 s = &dev->subdevices[bc.subdevice];
David Schleefed9eccb2008-11-04 20:29:31 -0800883 async = s->async;
884
885 if (!async) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -0700886 dev_dbg(dev->class_dev,
887 "subdevice does not have async capability\n");
David Schleefed9eccb2008-11-04 20:29:31 -0800888 bc.size = 0;
889 bc.maximum_size = 0;
890 goto copyback;
891 }
892
893 if (bc.maximum_size) {
894 if (!capable(CAP_SYS_ADMIN))
895 return -EPERM;
896
897 async->max_bufsize = bc.maximum_size;
898 }
899
900 if (bc.size) {
Ian Abbott482f0a22014-05-02 13:50:14 +0100901 retval = resize_async_buffer(dev, s, bc.size);
Frank Mori Hess883db3d2009-04-14 11:21:41 -0400902 if (retval < 0)
903 return retval;
David Schleefed9eccb2008-11-04 20:29:31 -0800904 }
905
906 bc.size = async->prealloc_bufsz;
907 bc.maximum_size = async->max_bufsize;
908
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800909copyback:
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700910 if (copy_to_user(arg, &bc, sizeof(bc)))
David Schleefed9eccb2008-11-04 20:29:31 -0800911 return -EFAULT;
912
913 return 0;
914}
915
916/*
Ian Abbott18e01b22015-01-28 18:41:47 +0000917 * COMEDI_DEVINFO ioctl
918 * device info
919 *
920 * arg:
921 * pointer to comedi_devinfo structure
922 *
923 * reads:
924 * nothing
925 *
926 * writes:
927 * comedi_devinfo structure
928 */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530929static int do_devinfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700930 struct comedi_devinfo __user *arg,
931 struct file *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800932{
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700933 struct comedi_subdevice *s;
934 struct comedi_devinfo devinfo;
David Schleefed9eccb2008-11-04 20:29:31 -0800935
Ian Abbott77c21b62019-04-17 15:39:29 +0100936 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -0800937 memset(&devinfo, 0, sizeof(devinfo));
938
939 /* fill devinfo structure */
940 devinfo.version_code = COMEDI_VERSION_CODE;
941 devinfo.n_subdevs = dev->n_subdevices;
Kumar Kartikeya Dwivedia91e4e02021-01-31 22:58:22 +0530942 strscpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
943 strscpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
David Schleefed9eccb2008-11-04 20:29:31 -0800944
Ian Abbott20f083c2014-11-04 18:09:00 +0000945 s = comedi_file_read_subdevice(file);
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700946 if (s)
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700947 devinfo.read_subdevice = s->index;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800948 else
David Schleefed9eccb2008-11-04 20:29:31 -0800949 devinfo.read_subdevice = -1;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800950
Ian Abbott20f083c2014-11-04 18:09:00 +0000951 s = comedi_file_write_subdevice(file);
H Hartley Sweeten0e700922012-12-19 15:39:18 -0700952 if (s)
H Hartley Sweeten90a35c12012-12-19 17:27:02 -0700953 devinfo.write_subdevice = s->index;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -0800954 else
David Schleefed9eccb2008-11-04 20:29:31 -0800955 devinfo.write_subdevice = -1;
David Schleefed9eccb2008-11-04 20:29:31 -0800956
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700957 if (copy_to_user(arg, &devinfo, sizeof(devinfo)))
David Schleefed9eccb2008-11-04 20:29:31 -0800958 return -EFAULT;
959
960 return 0;
961}
962
963/*
Ian Abbott18e01b22015-01-28 18:41:47 +0000964 * COMEDI_SUBDINFO ioctl
965 * subdevices info
966 *
967 * arg:
968 * pointer to array of comedi_subdinfo structures
969 *
970 * reads:
971 * nothing
972 *
973 * writes:
974 * array of comedi_subdinfo structures
975 */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530976static int do_subdinfo_ioctl(struct comedi_device *dev,
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -0700977 struct comedi_subdinfo __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800978{
979 int ret, i;
Bill Pembertonbd52efbb2009-03-16 22:06:09 -0400980 struct comedi_subdinfo *tmp, *us;
Bill Pemberton34c43922009-03-16 22:05:14 -0400981 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -0800982
Ian Abbott77c21b62019-04-17 15:39:29 +0100983 lockdep_assert_held(&dev->mutex);
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -0700984 tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL);
David Schleefed9eccb2008-11-04 20:29:31 -0800985 if (!tmp)
986 return -ENOMEM;
987
988 /* fill subdinfo structs */
989 for (i = 0; i < dev->n_subdevices; i++) {
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -0700990 s = &dev->subdevices[i];
David Schleefed9eccb2008-11-04 20:29:31 -0800991 us = tmp + i;
992
993 us->type = s->type;
994 us->n_chan = s->n_chan;
995 us->subd_flags = s->subdev_flags;
H Hartley Sweetenf0124632012-12-19 15:43:18 -0700996 if (comedi_is_subdevice_running(s))
David Schleefed9eccb2008-11-04 20:29:31 -0800997 us->subd_flags |= SDF_RUNNING;
998#define TIMER_nanosec 5 /* backwards compatibility */
999 us->timer_type = TIMER_nanosec;
1000 us->len_chanlist = s->len_chanlist;
1001 us->maxdata = s->maxdata;
1002 if (s->range_table) {
1003 us->range_type =
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001004 (i << 24) | (0 << 16) | (s->range_table->length);
David Schleefed9eccb2008-11-04 20:29:31 -08001005 } else {
1006 us->range_type = 0; /* XXX */
1007 }
David Schleefed9eccb2008-11-04 20:29:31 -08001008
1009 if (s->busy)
1010 us->subd_flags |= SDF_BUSY;
1011 if (s->busy == file)
1012 us->subd_flags |= SDF_BUSY_OWNER;
1013 if (s->lock)
1014 us->subd_flags |= SDF_LOCKED;
1015 if (s->lock == file)
1016 us->subd_flags |= SDF_LOCK_OWNER;
1017 if (!s->maxdata && s->maxdata_list)
1018 us->subd_flags |= SDF_MAXDATA;
David Schleefed9eccb2008-11-04 20:29:31 -08001019 if (s->range_table_list)
1020 us->subd_flags |= SDF_RANGETYPE;
1021 if (s->do_cmd)
1022 us->subd_flags |= SDF_CMD;
1023
1024 if (s->insn_bits != &insn_inval)
1025 us->insn_bits_support = COMEDI_SUPPORTED;
1026 else
1027 us->insn_bits_support = COMEDI_UNSUPPORTED;
David Schleefed9eccb2008-11-04 20:29:31 -08001028 }
1029
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001030 ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp));
David Schleefed9eccb2008-11-04 20:29:31 -08001031
1032 kfree(tmp);
1033
1034 return ret ? -EFAULT : 0;
1035}
1036
1037/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001038 * COMEDI_CHANINFO ioctl
1039 * subdevice channel info
1040 *
1041 * arg:
1042 * pointer to comedi_chaninfo structure
1043 *
1044 * reads:
1045 * comedi_chaninfo structure
1046 *
1047 * writes:
1048 * array of maxdata values to chaninfo->maxdata_list if requested
1049 * array of range table lengths to chaninfo->range_table_list if requested
1050 */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301051static int do_chaninfo_ioctl(struct comedi_device *dev,
Al Viro3fbfd222020-04-25 18:35:03 -04001052 struct comedi_chaninfo *it)
David Schleefed9eccb2008-11-04 20:29:31 -08001053{
Bill Pemberton34c43922009-03-16 22:05:14 -04001054 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001055
Ian Abbott77c21b62019-04-17 15:39:29 +01001056 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08001057
Al Viro3fbfd222020-04-25 18:35:03 -04001058 if (it->subdev >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -08001059 return -EINVAL;
Al Viro3fbfd222020-04-25 18:35:03 -04001060 s = &dev->subdevices[it->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001061
Al Viro3fbfd222020-04-25 18:35:03 -04001062 if (it->maxdata_list) {
David Schleefed9eccb2008-11-04 20:29:31 -08001063 if (s->maxdata || !s->maxdata_list)
1064 return -EINVAL;
Al Viro3fbfd222020-04-25 18:35:03 -04001065 if (copy_to_user(it->maxdata_list, s->maxdata_list,
Bill Pemberton790c5542009-03-16 22:05:02 -04001066 s->n_chan * sizeof(unsigned int)))
David Schleefed9eccb2008-11-04 20:29:31 -08001067 return -EFAULT;
1068 }
1069
Al Viro3fbfd222020-04-25 18:35:03 -04001070 if (it->flaglist)
Ian Abbott64d9b1d2013-10-07 16:50:05 +01001071 return -EINVAL; /* flaglist not supported */
David Schleefed9eccb2008-11-04 20:29:31 -08001072
Al Viro3fbfd222020-04-25 18:35:03 -04001073 if (it->rangelist) {
David Schleefed9eccb2008-11-04 20:29:31 -08001074 int i;
1075
1076 if (!s->range_table_list)
1077 return -EINVAL;
1078 for (i = 0; i < s->n_chan; i++) {
1079 int x;
1080
Al Viro3fbfd222020-04-25 18:35:03 -04001081 x = (dev->minor << 28) | (it->subdev << 24) | (i << 16) |
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001082 (s->range_table_list[i]->length);
Al Viro3fbfd222020-04-25 18:35:03 -04001083 if (put_user(x, it->rangelist + i))
Vasiliy Kulikov81604d42010-09-05 22:32:33 +04001084 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -08001085 }
David Schleefed9eccb2008-11-04 20:29:31 -08001086 }
1087
1088 return 0;
1089}
1090
Ian Abbott18e01b22015-01-28 18:41:47 +00001091/*
1092 * COMEDI_BUFINFO ioctl
1093 * buffer information
1094 *
1095 * arg:
1096 * pointer to comedi_bufinfo structure
1097 *
1098 * reads:
1099 * comedi_bufinfo structure
1100 *
1101 * writes:
1102 * modified comedi_bufinfo structure
1103 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001104static int do_bufinfo_ioctl(struct comedi_device *dev,
Ian Abbott53fa8272010-05-19 18:09:50 +01001105 struct comedi_bufinfo __user *arg, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001106{
Bill Pemberton9aa53392009-03-16 22:06:42 -04001107 struct comedi_bufinfo bi;
Bill Pemberton34c43922009-03-16 22:05:14 -04001108 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04001109 struct comedi_async *async;
Ian Abbott36a51172016-02-19 16:13:56 +00001110 unsigned int runflags;
1111 int retval = 0;
Ian Abbott06578562016-02-19 16:13:52 +00001112 bool become_nonbusy = false;
David Schleefed9eccb2008-11-04 20:29:31 -08001113
Ian Abbott77c21b62019-04-17 15:39:29 +01001114 lockdep_assert_held(&dev->mutex);
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001115 if (copy_from_user(&bi, arg, sizeof(bi)))
David Schleefed9eccb2008-11-04 20:29:31 -08001116 return -EFAULT;
1117
Güngör Erseymen7b1a5e22013-06-07 21:29:50 +03001118 if (bi.subdevice >= dev->n_subdevices)
David Schleefed9eccb2008-11-04 20:29:31 -08001119 return -EINVAL;
1120
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001121 s = &dev->subdevices[bi.subdevice];
Ian Abbott53fa8272010-05-19 18:09:50 +01001122
David Schleefed9eccb2008-11-04 20:29:31 -08001123 async = s->async;
1124
Ian Abbott57c563b2016-02-19 16:13:54 +00001125 if (!async || s->busy != file)
1126 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001127
Ian Abbottbe611a12016-02-19 16:13:57 +00001128 runflags = comedi_get_subdevice_runflags(s);
Ian Abbott66c36502016-02-19 16:13:51 +00001129 if (!(async->cmd.flags & CMDF_WRITE)) {
1130 /* command was set up in "read" direction */
1131 if (bi.bytes_read) {
1132 comedi_buf_read_alloc(s, bi.bytes_read);
1133 bi.bytes_read = comedi_buf_read_free(s, bi.bytes_read);
David Schleefed9eccb2008-11-04 20:29:31 -08001134 }
Ian Abbott36a51172016-02-19 16:13:56 +00001135 /*
1136 * If nothing left to read, and command has stopped, and
1137 * {"read" position not updated or command stopped normally},
1138 * then become non-busy.
1139 */
Ian Abbott36a51172016-02-19 16:13:56 +00001140 if (comedi_buf_read_n_available(s) == 0 &&
1141 !comedi_is_runflags_running(runflags) &&
1142 (bi.bytes_read == 0 ||
1143 !comedi_is_runflags_in_error(runflags))) {
Ian Abbottf3aa8c02016-02-19 16:13:55 +00001144 become_nonbusy = true;
Ian Abbott36a51172016-02-19 16:13:56 +00001145 if (comedi_is_runflags_in_error(runflags))
1146 retval = -EPIPE;
1147 }
Ian Abbott66c36502016-02-19 16:13:51 +00001148 bi.bytes_written = 0;
1149 } else {
1150 /* command was set up in "write" direction */
Ian Abbottbe611a12016-02-19 16:13:57 +00001151 if (!comedi_is_runflags_running(runflags)) {
Ian Abbottbb0c6bf2016-02-19 16:13:53 +00001152 bi.bytes_written = 0;
Ian Abbottbe611a12016-02-19 16:13:57 +00001153 become_nonbusy = true;
1154 if (comedi_is_runflags_in_error(runflags))
1155 retval = -EPIPE;
1156 } else if (bi.bytes_written) {
Ian Abbott66c36502016-02-19 16:13:51 +00001157 comedi_buf_write_alloc(s, bi.bytes_written);
1158 bi.bytes_written =
1159 comedi_buf_write_free(s, bi.bytes_written);
1160 }
1161 bi.bytes_read = 0;
David Schleefed9eccb2008-11-04 20:29:31 -08001162 }
1163
1164 bi.buf_write_count = async->buf_write_count;
1165 bi.buf_write_ptr = async->buf_write_ptr;
1166 bi.buf_read_count = async->buf_read_count;
1167 bi.buf_read_ptr = async->buf_read_ptr;
1168
Ian Abbott06578562016-02-19 16:13:52 +00001169 if (become_nonbusy)
1170 do_become_nonbusy(dev, s);
1171
Ian Abbott36a51172016-02-19 16:13:56 +00001172 if (retval)
1173 return retval;
1174
H Hartley Sweetenbc252fd2012-12-19 15:42:02 -07001175 if (copy_to_user(arg, &bi, sizeof(bi)))
David Schleefed9eccb2008-11-04 20:29:31 -08001176 return -EFAULT;
1177
1178 return 0;
1179}
1180
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301181static int check_insn_config_length(struct comedi_insn *insn,
1182 unsigned int *data)
David Schleefed9eccb2008-11-04 20:29:31 -08001183{
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001184 if (insn->n < 1)
1185 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001186
1187 switch (data[0]) {
1188 case INSN_CONFIG_DIO_OUTPUT:
1189 case INSN_CONFIG_DIO_INPUT:
1190 case INSN_CONFIG_DISARM:
1191 case INSN_CONFIG_RESET:
1192 if (insn->n == 1)
1193 return 0;
1194 break;
1195 case INSN_CONFIG_ARM:
1196 case INSN_CONFIG_DIO_QUERY:
1197 case INSN_CONFIG_BLOCK_SIZE:
1198 case INSN_CONFIG_FILTER:
1199 case INSN_CONFIG_SERIAL_CLOCK:
1200 case INSN_CONFIG_BIDIRECTIONAL_DATA:
1201 case INSN_CONFIG_ALT_SOURCE:
1202 case INSN_CONFIG_SET_COUNTER_MODE:
1203 case INSN_CONFIG_8254_READ_STATUS:
1204 case INSN_CONFIG_SET_ROUTING:
1205 case INSN_CONFIG_GET_ROUTING:
1206 case INSN_CONFIG_GET_PWM_STATUS:
1207 case INSN_CONFIG_PWM_SET_PERIOD:
1208 case INSN_CONFIG_PWM_GET_PERIOD:
1209 if (insn->n == 2)
1210 return 0;
1211 break;
1212 case INSN_CONFIG_SET_GATE_SRC:
1213 case INSN_CONFIG_GET_GATE_SRC:
1214 case INSN_CONFIG_SET_CLOCK_SRC:
1215 case INSN_CONFIG_GET_CLOCK_SRC:
1216 case INSN_CONFIG_SET_OTHER_SRC:
1217 case INSN_CONFIG_GET_COUNTER_STATUS:
1218 case INSN_CONFIG_PWM_SET_H_BRIDGE:
1219 case INSN_CONFIG_PWM_GET_H_BRIDGE:
1220 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
1221 if (insn->n == 3)
1222 return 0;
1223 break;
1224 case INSN_CONFIG_PWM_OUTPUT:
1225 case INSN_CONFIG_ANALOG_TRIG:
Ian Abbotte3b9ea92018-10-30 14:17:13 +00001226 case INSN_CONFIG_TIMER_1:
David Schleefed9eccb2008-11-04 20:29:31 -08001227 if (insn->n == 5)
1228 return 0;
1229 break;
Ian Abbottb0a2b6d2012-11-14 11:22:57 +00001230 case INSN_CONFIG_DIGITAL_TRIG:
1231 if (insn->n == 6)
1232 return 0;
1233 break;
Spencer E. Olson832f3332018-09-19 10:51:03 -06001234 case INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS:
1235 if (insn->n >= 4)
1236 return 0;
1237 break;
Ian Abbotta2aab8b2015-01-28 18:41:50 +00001238 /*
1239 * by default we allow the insn since we don't have checks for
1240 * all possible cases yet
1241 */
David Schleefed9eccb2008-11-04 20:29:31 -08001242 default:
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07001243 pr_warn("No check for data length of config insn id %i is implemented\n",
Ian Abbott4f870fe2012-08-16 14:38:05 +01001244 data[0]);
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07001245 pr_warn("Add a check to %s in %s\n", __func__, __FILE__);
1246 pr_warn("Assuming n=%i is correct\n", insn->n);
David Schleefed9eccb2008-11-04 20:29:31 -08001247 return 0;
David Schleefed9eccb2008-11-04 20:29:31 -08001248 }
1249 return -EINVAL;
1250}
1251
Spencer E. Olsond7569ad2018-10-03 14:56:02 -06001252static int check_insn_device_config_length(struct comedi_insn *insn,
1253 unsigned int *data)
1254{
1255 if (insn->n < 1)
1256 return -EINVAL;
1257
1258 switch (data[0]) {
1259 case INSN_DEVICE_CONFIG_TEST_ROUTE:
1260 case INSN_DEVICE_CONFIG_CONNECT_ROUTE:
1261 case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:
1262 if (insn->n == 3)
1263 return 0;
1264 break;
1265 case INSN_DEVICE_CONFIG_GET_ROUTES:
1266 /*
1267 * Big enough for config_id and the length of the userland
1268 * memory buffer. Additional length should be in factors of 2
1269 * to communicate any returned route pairs (source,destination).
1270 */
1271 if (insn->n >= 2)
1272 return 0;
1273 break;
1274 }
1275 return -EINVAL;
1276}
1277
1278/**
1279 * get_valid_routes() - Calls low-level driver get_valid_routes function to
1280 * either return a count of valid routes to user, or copy
1281 * of list of all valid device routes to buffer in
1282 * userspace.
1283 * @dev: comedi device pointer
1284 * @data: data from user insn call. The length of the data must be >= 2.
1285 * data[0] must contain the INSN_DEVICE_CONFIG config_id.
1286 * data[1](input) contains the number of _pairs_ for which memory is
1287 * allotted from the user. If the user specifies '0', then only
1288 * the number of pairs available is returned.
1289 * data[1](output) returns either the number of pairs available (if none
1290 * where requested) or the number of _pairs_ that are copied back
1291 * to the user.
1292 * data[2::2] returns each (source, destination) pair.
1293 *
1294 * Return: -EINVAL if low-level driver does not allocate and return routes as
1295 * expected. Returns 0 otherwise.
1296 */
1297static int get_valid_routes(struct comedi_device *dev, unsigned int *data)
1298{
Ian Abbott77c21b62019-04-17 15:39:29 +01001299 lockdep_assert_held(&dev->mutex);
Spencer E. Olsond7569ad2018-10-03 14:56:02 -06001300 data[1] = dev->get_valid_routes(dev, data[1], data + 2);
1301 return 0;
1302}
1303
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301304static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
1305 unsigned int *data, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001306{
Bill Pemberton34c43922009-03-16 22:05:14 -04001307 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001308 int ret = 0;
1309 int i;
1310
Ian Abbott77c21b62019-04-17 15:39:29 +01001311 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08001312 if (insn->insn & INSN_MASK_SPECIAL) {
1313 /* a non-subdevice instruction */
1314
1315 switch (insn->insn) {
1316 case INSN_GTOD:
1317 {
Arnd Bergmann70db3842016-06-17 21:56:15 +02001318 struct timespec64 tv;
David Schleefed9eccb2008-11-04 20:29:31 -08001319
1320 if (insn->n != 2) {
1321 ret = -EINVAL;
1322 break;
1323 }
1324
Arnd Bergmann70db3842016-06-17 21:56:15 +02001325 ktime_get_real_ts64(&tv);
1326 /* unsigned data safe until 2106 */
1327 data[0] = (unsigned int)tv.tv_sec;
1328 data[1] = tv.tv_nsec / NSEC_PER_USEC;
David Schleefed9eccb2008-11-04 20:29:31 -08001329 ret = 2;
1330
1331 break;
1332 }
1333 case INSN_WAIT:
1334 if (insn->n != 1 || data[0] >= 100000) {
1335 ret = -EINVAL;
1336 break;
1337 }
1338 udelay(data[0] / 1000);
1339 ret = 1;
1340 break;
1341 case INSN_INTTRIG:
1342 if (insn->n != 1) {
1343 ret = -EINVAL;
1344 break;
1345 }
1346 if (insn->subdev >= dev->n_subdevices) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001347 dev_dbg(dev->class_dev,
1348 "%d not usable subdevice\n",
David Schleefed9eccb2008-11-04 20:29:31 -08001349 insn->subdev);
1350 ret = -EINVAL;
1351 break;
1352 }
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001353 s = &dev->subdevices[insn->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001354 if (!s->async) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001355 dev_dbg(dev->class_dev, "no async\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001356 ret = -EINVAL;
1357 break;
1358 }
1359 if (!s->async->inttrig) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001360 dev_dbg(dev->class_dev, "no inttrig\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001361 ret = -EAGAIN;
1362 break;
1363 }
Ian Abbott5d06e3d2012-09-18 19:46:58 +01001364 ret = s->async->inttrig(dev, s, data[0]);
David Schleefed9eccb2008-11-04 20:29:31 -08001365 if (ret >= 0)
1366 ret = 1;
1367 break;
Spencer E. Olsond7569ad2018-10-03 14:56:02 -06001368 case INSN_DEVICE_CONFIG:
1369 ret = check_insn_device_config_length(insn, data);
1370 if (ret)
1371 break;
1372
1373 if (data[0] == INSN_DEVICE_CONFIG_GET_ROUTES) {
1374 /*
1375 * data[1] should be the number of _pairs_ that
1376 * the memory can hold.
1377 */
1378 data[1] = (insn->n - 2) / 2;
1379 ret = get_valid_routes(dev, data);
1380 break;
1381 }
1382
1383 /* other global device config instructions. */
1384 ret = dev->insn_device_config(dev, insn, data);
1385 break;
David Schleefed9eccb2008-11-04 20:29:31 -08001386 default:
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001387 dev_dbg(dev->class_dev, "invalid insn\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001388 ret = -EINVAL;
1389 break;
1390 }
1391 } else {
1392 /* a subdevice instruction */
Bill Pemberton790c5542009-03-16 22:05:02 -04001393 unsigned int maxdata;
David Schleefed9eccb2008-11-04 20:29:31 -08001394
1395 if (insn->subdev >= dev->n_subdevices) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001396 dev_dbg(dev->class_dev, "subdevice %d out of range\n",
1397 insn->subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001398 ret = -EINVAL;
1399 goto out;
1400 }
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001401 s = &dev->subdevices[insn->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001402
1403 if (s->type == COMEDI_SUBD_UNUSED) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001404 dev_dbg(dev->class_dev, "%d not usable subdevice\n",
1405 insn->subdev);
David Schleefed9eccb2008-11-04 20:29:31 -08001406 ret = -EIO;
1407 goto out;
1408 }
1409
1410 /* are we locked? (ioctl lock) */
1411 if (s->lock && s->lock != file) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001412 dev_dbg(dev->class_dev, "device locked\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001413 ret = -EACCES;
1414 goto out;
1415 }
1416
Greg Kroah-Hartman0fd0ca72010-05-01 12:33:17 -07001417 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001418 if (ret < 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001419 ret = -EINVAL;
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001420 dev_dbg(dev->class_dev, "bad chanspec\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001421 goto out;
1422 }
1423
1424 if (s->busy) {
1425 ret = -EBUSY;
1426 goto out;
1427 }
1428 /* This looks arbitrary. It is. */
Shraddha Barke30cc9bd2015-10-13 21:07:47 +05301429 s->busy = parse_insn;
David Schleefed9eccb2008-11-04 20:29:31 -08001430 switch (insn->insn) {
1431 case INSN_READ:
1432 ret = s->insn_read(dev, s, insn, data);
H Hartley Sweeten22ca19d2014-02-10 11:49:45 -07001433 if (ret == -ETIMEDOUT) {
1434 dev_dbg(dev->class_dev,
1435 "subdevice %d read instruction timed out\n",
1436 s->index);
1437 }
David Schleefed9eccb2008-11-04 20:29:31 -08001438 break;
1439 case INSN_WRITE:
1440 maxdata = s->maxdata_list
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001441 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1442 : s->maxdata;
David Schleefed9eccb2008-11-04 20:29:31 -08001443 for (i = 0; i < insn->n; ++i) {
1444 if (data[i] > maxdata) {
1445 ret = -EINVAL;
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001446 dev_dbg(dev->class_dev,
1447 "bad data value(s)\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001448 break;
1449 }
1450 }
H Hartley Sweeten22ca19d2014-02-10 11:49:45 -07001451 if (ret == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08001452 ret = s->insn_write(dev, s, insn, data);
H Hartley Sweeten22ca19d2014-02-10 11:49:45 -07001453 if (ret == -ETIMEDOUT) {
1454 dev_dbg(dev->class_dev,
1455 "subdevice %d write instruction timed out\n",
1456 s->index);
1457 }
1458 }
David Schleefed9eccb2008-11-04 20:29:31 -08001459 break;
1460 case INSN_BITS:
1461 if (insn->n != 2) {
1462 ret = -EINVAL;
Ian Abbott2f644cc2011-01-18 17:44:33 +00001463 } else {
Ian Abbotta2aab8b2015-01-28 18:41:50 +00001464 /*
1465 * Most drivers ignore the base channel in
Ian Abbott2f644cc2011-01-18 17:44:33 +00001466 * insn->chanspec. Fix this here if
Ian Abbotta2aab8b2015-01-28 18:41:50 +00001467 * the subdevice has <= 32 channels.
1468 */
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07001469 unsigned int orig_mask = data[0];
1470 unsigned int shift = 0;
Ian Abbott2f644cc2011-01-18 17:44:33 +00001471
Ian Abbott2f644cc2011-01-18 17:44:33 +00001472 if (s->n_chan <= 32) {
1473 shift = CR_CHAN(insn->chanspec);
1474 if (shift > 0) {
1475 insn->chanspec = 0;
1476 data[0] <<= shift;
1477 data[1] <<= shift;
1478 }
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07001479 }
Ian Abbott2f644cc2011-01-18 17:44:33 +00001480 ret = s->insn_bits(dev, s, insn, data);
1481 data[0] = orig_mask;
1482 if (shift > 0)
1483 data[1] >>= shift;
David Schleefed9eccb2008-11-04 20:29:31 -08001484 }
David Schleefed9eccb2008-11-04 20:29:31 -08001485 break;
1486 case INSN_CONFIG:
1487 ret = check_insn_config_length(insn, data);
1488 if (ret)
1489 break;
1490 ret = s->insn_config(dev, s, insn, data);
1491 break;
1492 default:
1493 ret = -EINVAL;
1494 break;
1495 }
1496
1497 s->busy = NULL;
1498 }
1499
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001500out:
David Schleefed9eccb2008-11-04 20:29:31 -08001501 return ret;
1502}
1503
1504/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001505 * COMEDI_INSNLIST ioctl
1506 * synchronous instruction list
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001507 *
Ian Abbott18e01b22015-01-28 18:41:47 +00001508 * arg:
1509 * pointer to comedi_insnlist structure
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001510 *
Ian Abbott18e01b22015-01-28 18:41:47 +00001511 * reads:
1512 * comedi_insnlist structure
1513 * array of comedi_insn structures from insnlist->insns pointer
1514 * data (for writes) from insns[].data pointers
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001515 *
Ian Abbott18e01b22015-01-28 18:41:47 +00001516 * writes:
1517 * data (for reads) to insns[].data pointers
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001518 */
1519/* arbitrary limits */
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001520#define MIN_SAMPLES 16
1521#define MAX_SAMPLES 65536
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001522static int do_insnlist_ioctl(struct comedi_device *dev,
Al Virob8d47d82020-04-25 20:33:04 -04001523 struct comedi_insn *insns,
1524 unsigned int n_insns,
1525 void *file)
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001526{
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001527 unsigned int *data = NULL;
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001528 unsigned int max_n_data_required = MIN_SAMPLES;
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001529 int i = 0;
1530 int ret = 0;
1531
Ian Abbott77c21b62019-04-17 15:39:29 +01001532 lockdep_assert_held(&dev->mutex);
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001533
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001534 /* Determine maximum memory needed for all instructions. */
Al Virob8d47d82020-04-25 20:33:04 -04001535 for (i = 0; i < n_insns; ++i) {
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001536 if (insns[i].n > MAX_SAMPLES) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001537 dev_dbg(dev->class_dev,
1538 "number of samples too large\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001539 ret = -EINVAL;
1540 goto error;
1541 }
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001542 max_n_data_required = max(max_n_data_required, insns[i].n);
1543 }
1544
1545 /* Allocate scratch space for all instruction data. */
1546 data = kmalloc_array(max_n_data_required, sizeof(unsigned int),
1547 GFP_KERNEL);
1548 if (!data) {
1549 ret = -ENOMEM;
1550 goto error;
1551 }
1552
Al Virob8d47d82020-04-25 20:33:04 -04001553 for (i = 0; i < n_insns; ++i) {
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001554 if (insns[i].insn & INSN_MASK_WRITE) {
1555 if (copy_from_user(data, insns[i].data,
1556 insns[i].n * sizeof(unsigned int))) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001557 dev_dbg(dev->class_dev,
1558 "copy_from_user failed\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001559 ret = -EFAULT;
1560 goto error;
1561 }
1562 }
1563 ret = parse_insn(dev, insns + i, data, file);
1564 if (ret < 0)
1565 goto error;
1566 if (insns[i].insn & INSN_MASK_READ) {
1567 if (copy_to_user(insns[i].data, data,
1568 insns[i].n * sizeof(unsigned int))) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001569 dev_dbg(dev->class_dev,
1570 "copy_to_user failed\n");
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001571 ret = -EFAULT;
1572 goto error;
1573 }
1574 }
1575 if (need_resched())
1576 schedule();
1577 }
1578
1579error:
H Hartley Sweeten5b6cbd82013-01-21 14:02:59 -07001580 kfree(data);
1581
1582 if (ret < 0)
1583 return ret;
1584 return i;
1585}
1586
1587/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001588 * COMEDI_INSN ioctl
1589 * synchronous instruction
David Schleefed9eccb2008-11-04 20:29:31 -08001590 *
Ian Abbott18e01b22015-01-28 18:41:47 +00001591 * arg:
1592 * pointer to comedi_insn structure
David Schleefed9eccb2008-11-04 20:29:31 -08001593 *
Ian Abbott18e01b22015-01-28 18:41:47 +00001594 * reads:
1595 * comedi_insn structure
1596 * data (for writes) from insn->data pointer
David Schleefed9eccb2008-11-04 20:29:31 -08001597 *
Ian Abbott18e01b22015-01-28 18:41:47 +00001598 * writes:
1599 * data (for reads) to insn->data pointer
David Schleefed9eccb2008-11-04 20:29:31 -08001600 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001601static int do_insn_ioctl(struct comedi_device *dev,
Al Viroaa332e62020-04-25 20:11:57 -04001602 struct comedi_insn *insn, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001603{
Bill Pemberton790c5542009-03-16 22:05:02 -04001604 unsigned int *data = NULL;
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001605 unsigned int n_data = MIN_SAMPLES;
David Schleefed9eccb2008-11-04 20:29:31 -08001606 int ret = 0;
1607
Ian Abbott77c21b62019-04-17 15:39:29 +01001608 lockdep_assert_held(&dev->mutex);
Jitendra Khasdev56eec182019-01-15 21:06:56 +05301609
Al Viroaa332e62020-04-25 20:11:57 -04001610 n_data = max(n_data, insn->n);
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001611
1612 /* This is where the behavior of insn and insnlist deviate. */
Al Viroaa332e62020-04-25 20:11:57 -04001613 if (insn->n > MAX_SAMPLES) {
1614 insn->n = MAX_SAMPLES;
Spencer E. Olsonf8bc1b22018-12-04 12:07:50 -07001615 n_data = MAX_SAMPLES;
1616 }
1617
1618 data = kmalloc_array(n_data, sizeof(unsigned int), GFP_KERNEL);
David Schleefed9eccb2008-11-04 20:29:31 -08001619 if (!data) {
1620 ret = -ENOMEM;
1621 goto error;
1622 }
1623
Al Viroaa332e62020-04-25 20:11:57 -04001624 if (insn->insn & INSN_MASK_WRITE) {
Mark21fe2ee2010-05-13 17:44:39 +08001625 if (copy_from_user(data,
Al Viroaa332e62020-04-25 20:11:57 -04001626 insn->data,
1627 insn->n * sizeof(unsigned int))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001628 ret = -EFAULT;
1629 goto error;
1630 }
1631 }
Al Viroaa332e62020-04-25 20:11:57 -04001632 ret = parse_insn(dev, insn, data, file);
David Schleefed9eccb2008-11-04 20:29:31 -08001633 if (ret < 0)
1634 goto error;
Al Viroaa332e62020-04-25 20:11:57 -04001635 if (insn->insn & INSN_MASK_READ) {
1636 if (copy_to_user(insn->data,
Mark21fe2ee2010-05-13 17:44:39 +08001637 data,
Al Viroaa332e62020-04-25 20:11:57 -04001638 insn->n * sizeof(unsigned int))) {
David Schleefed9eccb2008-11-04 20:29:31 -08001639 ret = -EFAULT;
1640 goto error;
1641 }
1642 }
Al Viroaa332e62020-04-25 20:11:57 -04001643 ret = insn->n;
David Schleefed9eccb2008-11-04 20:29:31 -08001644
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001645error:
1646 kfree(data);
David Schleefed9eccb2008-11-04 20:29:31 -08001647
1648 return ret;
1649}
1650
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001651static int __comedi_get_user_cmd(struct comedi_device *dev,
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001652 struct comedi_cmd *cmd)
1653{
1654 struct comedi_subdevice *s;
1655
Ian Abbott77c21b62019-04-17 15:39:29 +01001656 lockdep_assert_held(&dev->mutex);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001657 if (cmd->subdev >= dev->n_subdevices) {
1658 dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev);
1659 return -ENODEV;
1660 }
1661
1662 s = &dev->subdevices[cmd->subdev];
1663
1664 if (s->type == COMEDI_SUBD_UNUSED) {
Yves Deweerdtb2f48742014-03-31 22:55:39 +02001665 dev_dbg(dev->class_dev, "%d not valid subdevice\n",
1666 cmd->subdev);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001667 return -EIO;
1668 }
1669
1670 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1671 dev_dbg(dev->class_dev,
Yves Deweerdtb2f48742014-03-31 22:55:39 +02001672 "subdevice %d does not support commands\n",
1673 cmd->subdev);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001674 return -EIO;
1675 }
1676
1677 /* make sure channel/gain list isn't too long */
1678 if (cmd->chanlist_len > s->len_chanlist) {
1679 dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n",
1680 cmd->chanlist_len, s->len_chanlist);
1681 return -EINVAL;
1682 }
1683
Ian Abbott5d070cf2014-10-30 12:42:26 +00001684 /*
1685 * Set the CMDF_WRITE flag to the correct state if the subdevice
1686 * supports only "read" commands or only "write" commands.
1687 */
1688 switch (s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) {
1689 case SDF_CMD_READ:
1690 cmd->flags &= ~CMDF_WRITE;
1691 break;
1692 case SDF_CMD_WRITE:
1693 cmd->flags |= CMDF_WRITE;
1694 break;
1695 default:
1696 break;
1697 }
1698
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001699 return 0;
1700}
1701
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001702static int __comedi_get_user_chanlist(struct comedi_device *dev,
1703 struct comedi_subdevice *s,
1704 unsigned int __user *user_chanlist,
1705 struct comedi_cmd *cmd)
1706{
1707 unsigned int *chanlist;
1708 int ret;
1709
Ian Abbott77c21b62019-04-17 15:39:29 +01001710 lockdep_assert_held(&dev->mutex);
Ian Abbott238b5ad2014-10-20 15:10:40 +01001711 cmd->chanlist = NULL;
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001712 chanlist = memdup_user(user_chanlist,
1713 cmd->chanlist_len * sizeof(unsigned int));
1714 if (IS_ERR(chanlist))
1715 return PTR_ERR(chanlist);
1716
1717 /* make sure each element in channel/gain list is valid */
1718 ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist);
1719 if (ret < 0) {
1720 kfree(chanlist);
1721 return ret;
1722 }
1723
1724 cmd->chanlist = chanlist;
1725
1726 return 0;
1727}
1728
Ian Abbott18e01b22015-01-28 18:41:47 +00001729/*
1730 * COMEDI_CMD ioctl
1731 * asynchronous acquisition command set-up
1732 *
1733 * arg:
1734 * pointer to comedi_cmd structure
1735 *
1736 * reads:
1737 * comedi_cmd structure
1738 * channel/range list from cmd->chanlist pointer
1739 *
1740 * writes:
1741 * possibly modified comedi_cmd structure (when -EAGAIN returned)
1742 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001743static int do_cmd_ioctl(struct comedi_device *dev,
Al Viro0a3ccc72020-04-26 09:01:49 -04001744 struct comedi_cmd *cmd, bool *copy, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001745{
Bill Pemberton34c43922009-03-16 22:05:14 -04001746 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04001747 struct comedi_async *async;
H Hartley Sweeten95bc359f2012-09-18 11:43:52 -07001748 unsigned int __user *user_chanlist;
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001749 int ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001750
Ian Abbott77c21b62019-04-17 15:39:29 +01001751 lockdep_assert_held(&dev->mutex);
1752
Al Viro0a3ccc72020-04-26 09:01:49 -04001753 /* do some simple cmd validation */
1754 ret = __comedi_get_user_cmd(dev, cmd);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001755 if (ret)
1756 return ret;
1757
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001758 /* save user's chanlist pointer so it can be restored later */
Al Viro0a3ccc72020-04-26 09:01:49 -04001759 user_chanlist = (unsigned int __user *)cmd->chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001760
Al Viro0a3ccc72020-04-26 09:01:49 -04001761 s = &dev->subdevices[cmd->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001762 async = s->async;
1763
David Schleefed9eccb2008-11-04 20:29:31 -08001764 /* are we locked? (ioctl lock) */
1765 if (s->lock && s->lock != file) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001766 dev_dbg(dev->class_dev, "subdevice locked\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001767 return -EACCES;
1768 }
1769
1770 /* are we busy? */
1771 if (s->busy) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001772 dev_dbg(dev->class_dev, "subdevice busy\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001773 return -EBUSY;
1774 }
David Schleefed9eccb2008-11-04 20:29:31 -08001775
David Schleefed9eccb2008-11-04 20:29:31 -08001776 /* make sure channel/gain list isn't too short */
Al Viro0a3ccc72020-04-26 09:01:49 -04001777 if (cmd->chanlist_len < 1) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001778 dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n",
Al Viro0a3ccc72020-04-26 09:01:49 -04001779 cmd->chanlist_len);
Ian Abbott4b18f082013-07-05 16:49:34 +01001780 return -EINVAL;
David Schleefed9eccb2008-11-04 20:29:31 -08001781 }
1782
Al Viro0a3ccc72020-04-26 09:01:49 -04001783 async->cmd = *cmd;
David Schleefed9eccb2008-11-04 20:29:31 -08001784 async->cmd.data = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001785
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001786 /* load channel/gain list */
1787 ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd);
1788 if (ret)
David Schleefed9eccb2008-11-04 20:29:31 -08001789 goto cleanup;
David Schleefed9eccb2008-11-04 20:29:31 -08001790
1791 ret = s->do_cmdtest(dev, s, &async->cmd);
1792
Ian Abbottb0446a22014-09-03 13:45:44 +01001793 if (async->cmd.flags & CMDF_BOGUS || ret) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001794 dev_dbg(dev->class_dev, "test returned %d\n", ret);
Al Viro0a3ccc72020-04-26 09:01:49 -04001795 *cmd = async->cmd;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001796 /* restore chanlist pointer before copying back */
Al Viro0a3ccc72020-04-26 09:01:49 -04001797 cmd->chanlist = (unsigned int __force *)user_chanlist;
1798 cmd->data = NULL;
1799 *copy = true;
David Schleefed9eccb2008-11-04 20:29:31 -08001800 ret = -EAGAIN;
1801 goto cleanup;
1802 }
1803
1804 if (!async->prealloc_bufsz) {
1805 ret = -ENOMEM;
H Hartley Sweeten272850f2013-11-26 10:21:11 -07001806 dev_dbg(dev->class_dev, "no buffer (?)\n");
David Schleefed9eccb2008-11-04 20:29:31 -08001807 goto cleanup;
1808 }
1809
Ian Abbottfcc18a92014-05-06 13:12:10 +01001810 comedi_buf_reset(s);
David Schleefed9eccb2008-11-04 20:29:31 -08001811
H Hartley Sweeten781f9332014-10-13 09:56:08 -07001812 async->cb_mask = COMEDI_CB_BLOCK | COMEDI_CB_CANCEL_MASK;
Ian Abbottd8bff6e2014-09-03 13:45:30 +01001813 if (async->cmd.flags & CMDF_WAKE_EOS)
David Schleefed9eccb2008-11-04 20:29:31 -08001814 async->cb_mask |= COMEDI_CB_EOS;
David Schleefed9eccb2008-11-04 20:29:31 -08001815
Ian Abbottcc64ea42015-03-27 15:13:00 +00001816 comedi_update_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
1817 COMEDI_SRF_RUNNING);
David Schleefed9eccb2008-11-04 20:29:31 -08001818
H Hartley Sweeten84bb0bc2015-01-20 12:06:00 -07001819 /*
1820 * Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
1821 * race with comedi_read() or comedi_write().
1822 */
Ian Abbott4b18f082013-07-05 16:49:34 +01001823 s->busy = file;
David Schleefed9eccb2008-11-04 20:29:31 -08001824 ret = s->do_cmd(dev, s);
1825 if (ret == 0)
1826 return 0;
1827
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001828cleanup:
David Schleefed9eccb2008-11-04 20:29:31 -08001829 do_become_nonbusy(dev, s);
1830
1831 return ret;
1832}
1833
1834/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001835 * COMEDI_CMDTEST ioctl
Carlos E. Garcia69e98df2015-04-24 09:40:42 -04001836 * asynchronous acquisition command testing
Ian Abbott18e01b22015-01-28 18:41:47 +00001837 *
1838 * arg:
1839 * pointer to comedi_cmd structure
1840 *
1841 * reads:
1842 * comedi_cmd structure
1843 * channel/range list from cmd->chanlist pointer
1844 *
1845 * writes:
1846 * possibly modified comedi_cmd structure
1847 */
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07001848static int do_cmdtest_ioctl(struct comedi_device *dev,
Al Virof0e4de52020-04-26 08:56:55 -04001849 struct comedi_cmd *cmd, bool *copy, void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001850{
Bill Pemberton34c43922009-03-16 22:05:14 -04001851 struct comedi_subdevice *s;
H Hartley Sweeten95bc359f2012-09-18 11:43:52 -07001852 unsigned int __user *user_chanlist;
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001853 int ret;
David Schleefed9eccb2008-11-04 20:29:31 -08001854
Ian Abbott77c21b62019-04-17 15:39:29 +01001855 lockdep_assert_held(&dev->mutex);
1856
Al Virof0e4de52020-04-26 08:56:55 -04001857 /* do some simple cmd validation */
1858 ret = __comedi_get_user_cmd(dev, cmd);
H Hartley Sweeten87ece582014-03-06 12:02:56 -07001859 if (ret)
1860 return ret;
1861
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001862 /* save user's chanlist pointer so it can be restored later */
Al Virof0e4de52020-04-26 08:56:55 -04001863 user_chanlist = (unsigned int __user *)cmd->chanlist;
David Schleefed9eccb2008-11-04 20:29:31 -08001864
Al Virof0e4de52020-04-26 08:56:55 -04001865 s = &dev->subdevices[cmd->subdev];
David Schleefed9eccb2008-11-04 20:29:31 -08001866
Ian Abbott6cab7a32014-10-08 16:09:14 +01001867 /* user_chanlist can be NULL for COMEDI_CMDTEST ioctl */
1868 if (user_chanlist) {
1869 /* load channel/gain list */
Al Virof0e4de52020-04-26 08:56:55 -04001870 ret = __comedi_get_user_chanlist(dev, s, user_chanlist, cmd);
Ian Abbott6cab7a32014-10-08 16:09:14 +01001871 if (ret)
1872 return ret;
1873 }
David Schleefed9eccb2008-11-04 20:29:31 -08001874
Al Virof0e4de52020-04-26 08:56:55 -04001875 ret = s->do_cmdtest(dev, s, cmd);
David Schleefed9eccb2008-11-04 20:29:31 -08001876
Al Virof0e4de52020-04-26 08:56:55 -04001877 kfree(cmd->chanlist); /* free kernel copy of user chanlist */
Ian Abbott238b5ad2014-10-20 15:10:40 +01001878
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001879 /* restore chanlist pointer before copying back */
Al Virof0e4de52020-04-26 08:56:55 -04001880 cmd->chanlist = (unsigned int __force *)user_chanlist;
1881 *copy = true;
H Hartley Sweetenc6cd0ee2014-03-06 12:02:57 -07001882
David Schleefed9eccb2008-11-04 20:29:31 -08001883 return ret;
1884}
1885
1886/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001887 * COMEDI_LOCK ioctl
1888 * lock subdevice
1889 *
1890 * arg:
1891 * subdevice number
1892 *
1893 * reads:
1894 * nothing
1895 *
1896 * writes:
1897 * nothing
1898 */
Ian Abbottc1a6eac2014-10-28 17:15:47 +00001899static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301900 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001901{
1902 int ret = 0;
1903 unsigned long flags;
Bill Pemberton34c43922009-03-16 22:05:14 -04001904 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001905
Ian Abbott77c21b62019-04-17 15:39:29 +01001906 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08001907 if (arg >= dev->n_subdevices)
1908 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001909 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001910
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001911 spin_lock_irqsave(&s->spin_lock, flags);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001912 if (s->busy || s->lock)
David Schleefed9eccb2008-11-04 20:29:31 -08001913 ret = -EBUSY;
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08001914 else
David Schleefed9eccb2008-11-04 20:29:31 -08001915 s->lock = file;
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001916 spin_unlock_irqrestore(&s->spin_lock, flags);
David Schleefed9eccb2008-11-04 20:29:31 -08001917
David Schleefed9eccb2008-11-04 20:29:31 -08001918 return ret;
1919}
1920
1921/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001922 * COMEDI_UNLOCK ioctl
1923 * unlock subdevice
1924 *
1925 * arg:
1926 * subdevice number
1927 *
1928 * reads:
1929 * nothing
1930 *
1931 * writes:
1932 * nothing
1933 */
Ian Abbottc1a6eac2014-10-28 17:15:47 +00001934static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301935 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001936{
Bill Pemberton34c43922009-03-16 22:05:14 -04001937 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001938
Ian Abbott77c21b62019-04-17 15:39:29 +01001939 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08001940 if (arg >= dev->n_subdevices)
1941 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001942 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08001943
1944 if (s->busy)
1945 return -EBUSY;
1946
1947 if (s->lock && s->lock != file)
1948 return -EACCES;
1949
H Hartley Sweeten90ac0762014-07-21 11:01:26 -07001950 if (s->lock == file)
David Schleefed9eccb2008-11-04 20:29:31 -08001951 s->lock = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08001952
1953 return 0;
1954}
1955
1956/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001957 * COMEDI_CANCEL ioctl
1958 * cancel asynchronous acquisition
1959 *
1960 * arg:
1961 * subdevice number
1962 *
1963 * reads:
1964 * nothing
1965 *
1966 * writes:
1967 * nothing
1968 */
Ian Abbottc1a6eac2014-10-28 17:15:47 +00001969static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05301970 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08001971{
Bill Pemberton34c43922009-03-16 22:05:14 -04001972 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08001973
Ian Abbott77c21b62019-04-17 15:39:29 +01001974 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08001975 if (arg >= dev->n_subdevices)
1976 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07001977 s = &dev->subdevices[arg];
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -07001978 if (!s->async)
David Schleefed9eccb2008-11-04 20:29:31 -08001979 return -EINVAL;
1980
David Schleefed9eccb2008-11-04 20:29:31 -08001981 if (!s->busy)
1982 return 0;
1983
1984 if (s->busy != file)
1985 return -EBUSY;
1986
Heena Sirwanife43ec52014-10-06 13:46:09 +05301987 return do_cancel(dev, s);
David Schleefed9eccb2008-11-04 20:29:31 -08001988}
1989
1990/*
Ian Abbott18e01b22015-01-28 18:41:47 +00001991 * COMEDI_POLL ioctl
1992 * instructs driver to synchronize buffers
1993 *
1994 * arg:
1995 * subdevice number
1996 *
1997 * reads:
1998 * nothing
1999 *
2000 * writes:
2001 * nothing
2002 */
Ian Abbottc1a6eac2014-10-28 17:15:47 +00002003static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05302004 void *file)
David Schleefed9eccb2008-11-04 20:29:31 -08002005{
Bill Pemberton34c43922009-03-16 22:05:14 -04002006 struct comedi_subdevice *s;
David Schleefed9eccb2008-11-04 20:29:31 -08002007
Ian Abbott77c21b62019-04-17 15:39:29 +01002008 lockdep_assert_held(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002009 if (arg >= dev->n_subdevices)
2010 return -EINVAL;
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07002011 s = &dev->subdevices[arg];
David Schleefed9eccb2008-11-04 20:29:31 -08002012
David Schleefed9eccb2008-11-04 20:29:31 -08002013 if (!s->busy)
2014 return 0;
2015
2016 if (s->busy != file)
2017 return -EBUSY;
2018
2019 if (s->poll)
2020 return s->poll(dev, s);
2021
2022 return -EINVAL;
2023}
2024
Ian Abbottc299a672014-11-04 18:09:01 +00002025/*
2026 * COMEDI_SETRSUBD ioctl
2027 * sets the current "read" subdevice on a per-file basis
2028 *
2029 * arg:
2030 * subdevice number
2031 *
2032 * reads:
2033 * nothing
2034 *
2035 * writes:
2036 * nothing
2037 */
2038static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg,
2039 struct file *file)
2040{
2041 struct comedi_file *cfp = file->private_data;
2042 struct comedi_subdevice *s_old, *s_new;
2043
Ian Abbott77c21b62019-04-17 15:39:29 +01002044 lockdep_assert_held(&dev->mutex);
Ian Abbottc299a672014-11-04 18:09:01 +00002045 if (arg >= dev->n_subdevices)
2046 return -EINVAL;
2047
2048 s_new = &dev->subdevices[arg];
2049 s_old = comedi_file_read_subdevice(file);
2050 if (s_old == s_new)
2051 return 0; /* no change */
2052
2053 if (!(s_new->subdev_flags & SDF_CMD_READ))
2054 return -EINVAL;
2055
2056 /*
2057 * Check the file isn't still busy handling a "read" command on the
2058 * old subdevice (if any).
2059 */
2060 if (s_old && s_old->busy == file && s_old->async &&
2061 !(s_old->async->cmd.flags & CMDF_WRITE))
2062 return -EBUSY;
2063
Shyam Saini34d34732016-05-10 21:21:07 +05302064 WRITE_ONCE(cfp->read_subdev, s_new);
Ian Abbottc299a672014-11-04 18:09:01 +00002065 return 0;
2066}
2067
2068/*
2069 * COMEDI_SETWSUBD ioctl
2070 * sets the current "write" subdevice on a per-file basis
2071 *
2072 * arg:
2073 * subdevice number
2074 *
2075 * reads:
2076 * nothing
2077 *
2078 * writes:
2079 * nothing
2080 */
2081static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg,
2082 struct file *file)
2083{
2084 struct comedi_file *cfp = file->private_data;
2085 struct comedi_subdevice *s_old, *s_new;
2086
Ian Abbott77c21b62019-04-17 15:39:29 +01002087 lockdep_assert_held(&dev->mutex);
Ian Abbottc299a672014-11-04 18:09:01 +00002088 if (arg >= dev->n_subdevices)
2089 return -EINVAL;
2090
2091 s_new = &dev->subdevices[arg];
2092 s_old = comedi_file_write_subdevice(file);
2093 if (s_old == s_new)
2094 return 0; /* no change */
2095
2096 if (!(s_new->subdev_flags & SDF_CMD_WRITE))
2097 return -EINVAL;
2098
2099 /*
2100 * Check the file isn't still busy handling a "write" command on the
2101 * old subdevice (if any).
2102 */
2103 if (s_old && s_old->busy == file && s_old->async &&
2104 (s_old->async->cmd.flags & CMDF_WRITE))
2105 return -EBUSY;
2106
Shyam Saini34d34732016-05-10 21:21:07 +05302107 WRITE_ONCE(cfp->write_subdev, s_new);
Ian Abbottc299a672014-11-04 18:09:01 +00002108 return 0;
2109}
2110
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002111static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
2112 unsigned long arg)
2113{
Leslie Kleind4d47892016-03-21 09:18:35 -04002114 unsigned int minor = iminor(file_inode(file));
Ian Abbott20f083c2014-11-04 18:09:00 +00002115 struct comedi_file *cfp = file->private_data;
2116 struct comedi_device *dev = cfp->dev;
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002117 int rc;
2118
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002119 mutex_lock(&dev->mutex);
2120
Ian Abbotta2aab8b2015-01-28 18:41:50 +00002121 /*
2122 * Device config is special, because it must work on
2123 * an unconfigured device.
2124 */
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002125 if (cmd == COMEDI_DEVCONFIG) {
Ian Abbott754ab5c2013-01-28 16:14:31 +00002126 if (minor >= COMEDI_NUM_BOARD_MINORS) {
2127 /* Device config not appropriate on non-board minors. */
2128 rc = -ENOTTY;
2129 goto done;
2130 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002131 rc = do_devconfig_ioctl(dev,
2132 (struct comedi_devconfig __user *)arg);
Ian Abbott8ab4ed62013-04-04 14:58:54 +01002133 if (rc == 0) {
2134 if (arg == 0 &&
2135 dev->minor >= comedi_num_legacy_minors) {
Ian Abbotta2aab8b2015-01-28 18:41:50 +00002136 /*
2137 * Successfully unconfigured a dynamically
2138 * allocated device. Try and remove it.
2139 */
Ian Abbottdb210da2013-04-04 14:59:18 +01002140 if (comedi_clear_board_dev(dev)) {
Ian Abbott8ab4ed62013-04-04 14:58:54 +01002141 mutex_unlock(&dev->mutex);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01002142 comedi_free_board_dev(dev);
Ian Abbott8ab4ed62013-04-04 14:58:54 +01002143 return rc;
2144 }
2145 }
2146 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002147 goto done;
2148 }
2149
2150 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002151 dev_dbg(dev->class_dev, "no driver attached\n");
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002152 rc = -ENODEV;
2153 goto done;
2154 }
2155
2156 switch (cmd) {
2157 case COMEDI_BUFCONFIG:
2158 rc = do_bufconfig_ioctl(dev,
2159 (struct comedi_bufconfig __user *)arg);
2160 break;
2161 case COMEDI_DEVINFO:
2162 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
2163 file);
2164 break;
2165 case COMEDI_SUBDINFO:
2166 rc = do_subdinfo_ioctl(dev,
2167 (struct comedi_subdinfo __user *)arg,
2168 file);
2169 break;
Al Viro3fbfd222020-04-25 18:35:03 -04002170 case COMEDI_CHANINFO: {
2171 struct comedi_chaninfo it;
Divyansh Kamboj76cd0c72020-06-05 08:51:40 +05302172
Al Viro3fbfd222020-04-25 18:35:03 -04002173 if (copy_from_user(&it, (void __user *)arg, sizeof(it)))
2174 rc = -EFAULT;
2175 else
2176 rc = do_chaninfo_ioctl(dev, &it);
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002177 break;
Al Viro3fbfd222020-04-25 18:35:03 -04002178 }
Al Viro38813872020-04-25 18:44:30 -04002179 case COMEDI_RANGEINFO: {
2180 struct comedi_rangeinfo it;
Divyansh Kamboj76cd0c72020-06-05 08:51:40 +05302181
Al Viro38813872020-04-25 18:44:30 -04002182 if (copy_from_user(&it, (void __user *)arg, sizeof(it)))
2183 rc = -EFAULT;
2184 else
2185 rc = do_rangeinfo_ioctl(dev, &it);
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002186 break;
Al Viro38813872020-04-25 18:44:30 -04002187 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002188 case COMEDI_BUFINFO:
2189 rc = do_bufinfo_ioctl(dev,
2190 (struct comedi_bufinfo __user *)arg,
2191 file);
2192 break;
2193 case COMEDI_LOCK:
2194 rc = do_lock_ioctl(dev, arg, file);
2195 break;
2196 case COMEDI_UNLOCK:
2197 rc = do_unlock_ioctl(dev, arg, file);
2198 break;
2199 case COMEDI_CANCEL:
2200 rc = do_cancel_ioctl(dev, arg, file);
2201 break;
Al Viro0a3ccc72020-04-26 09:01:49 -04002202 case COMEDI_CMD: {
2203 struct comedi_cmd cmd;
2204 bool copy = false;
2205
2206 if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd))) {
2207 rc = -EFAULT;
2208 break;
2209 }
2210 rc = do_cmd_ioctl(dev, &cmd, &copy, file);
2211 if (copy && copy_to_user((void __user *)arg, &cmd, sizeof(cmd)))
2212 rc = -EFAULT;
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002213 break;
Al Viro0a3ccc72020-04-26 09:01:49 -04002214 }
Al Virof0e4de52020-04-26 08:56:55 -04002215 case COMEDI_CMDTEST: {
2216 struct comedi_cmd cmd;
2217 bool copy = false;
2218
2219 if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd))) {
2220 rc = -EFAULT;
2221 break;
2222 }
2223 rc = do_cmdtest_ioctl(dev, &cmd, &copy, file);
2224 if (copy && copy_to_user((void __user *)arg, &cmd, sizeof(cmd)))
2225 rc = -EFAULT;
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002226 break;
Al Virof0e4de52020-04-26 08:56:55 -04002227 }
Al Virob8d47d82020-04-25 20:33:04 -04002228 case COMEDI_INSNLIST: {
2229 struct comedi_insnlist insnlist;
2230 struct comedi_insn *insns = NULL;
2231
2232 if (copy_from_user(&insnlist, (void __user *)arg,
2233 sizeof(insnlist))) {
2234 rc = -EFAULT;
2235 break;
2236 }
2237 insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
2238 if (!insns) {
2239 rc = -ENOMEM;
2240 break;
2241 }
2242 if (copy_from_user(insns, insnlist.insns,
2243 sizeof(*insns) * insnlist.n_insns)) {
2244 rc = -EFAULT;
2245 kfree(insns);
2246 break;
2247 }
2248 rc = do_insnlist_ioctl(dev, insns, insnlist.n_insns, file);
2249 kfree(insns);
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002250 break;
Al Virob8d47d82020-04-25 20:33:04 -04002251 }
Al Viroaa332e62020-04-25 20:11:57 -04002252 case COMEDI_INSN: {
2253 struct comedi_insn insn;
Divyansh Kamboj76cd0c72020-06-05 08:51:40 +05302254
Al Viroaa332e62020-04-25 20:11:57 -04002255 if (copy_from_user(&insn, (void __user *)arg, sizeof(insn)))
2256 rc = -EFAULT;
2257 else
2258 rc = do_insn_ioctl(dev, &insn, file);
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002259 break;
Al Viroaa332e62020-04-25 20:11:57 -04002260 }
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002261 case COMEDI_POLL:
2262 rc = do_poll_ioctl(dev, arg, file);
2263 break;
Ian Abbottc299a672014-11-04 18:09:01 +00002264 case COMEDI_SETRSUBD:
2265 rc = do_setrsubd_ioctl(dev, arg, file);
2266 break;
2267 case COMEDI_SETWSUBD:
2268 rc = do_setwsubd_ioctl(dev, arg, file);
2269 break;
H Hartley Sweeten47db6d52012-06-07 17:05:27 -07002270 default:
2271 rc = -ENOTTY;
2272 break;
2273 }
2274
2275done:
2276 mutex_unlock(&dev->mutex);
2277 return rc;
2278}
2279
Federico Vagadf30b212011-10-29 09:45:39 +02002280static void comedi_vm_open(struct vm_area_struct *area)
2281{
Ian Abbottaf93da32013-11-08 15:03:43 +00002282 struct comedi_buf_map *bm;
Federico Vagadf30b212011-10-29 09:45:39 +02002283
Ian Abbottaf93da32013-11-08 15:03:43 +00002284 bm = area->vm_private_data;
2285 comedi_buf_map_get(bm);
Federico Vagadf30b212011-10-29 09:45:39 +02002286}
2287
2288static void comedi_vm_close(struct vm_area_struct *area)
David Schleefed9eccb2008-11-04 20:29:31 -08002289{
Ian Abbottaf93da32013-11-08 15:03:43 +00002290 struct comedi_buf_map *bm;
David Schleefed9eccb2008-11-04 20:29:31 -08002291
Ian Abbottaf93da32013-11-08 15:03:43 +00002292 bm = area->vm_private_data;
2293 comedi_buf_map_put(bm);
David Schleefed9eccb2008-11-04 20:29:31 -08002294}
2295
Ian Abbott255364f2017-04-20 19:05:14 +01002296static int comedi_vm_access(struct vm_area_struct *vma, unsigned long addr,
2297 void *buf, int len, int write)
2298{
2299 struct comedi_buf_map *bm = vma->vm_private_data;
2300 unsigned long offset =
2301 addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT);
2302
2303 if (len < 0)
2304 return -EINVAL;
2305 if (len > vma->vm_end - addr)
2306 len = vma->vm_end - addr;
2307 return comedi_buf_map_access(bm, offset, buf, len, write);
2308}
2309
Kirill A. Shutemov7cbea8d2015-09-09 15:39:26 -07002310static const struct vm_operations_struct comedi_vm_ops = {
Federico Vagadf30b212011-10-29 09:45:39 +02002311 .open = comedi_vm_open,
2312 .close = comedi_vm_close,
Ian Abbott255364f2017-04-20 19:05:14 +01002313 .access = comedi_vm_access,
David Schleefed9eccb2008-11-04 20:29:31 -08002314};
2315
2316static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
2317{
Ian Abbott20f083c2014-11-04 18:09:00 +00002318 struct comedi_file *cfp = file->private_data;
2319 struct comedi_device *dev = cfp->dev;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002320 struct comedi_subdevice *s;
2321 struct comedi_async *async;
Ian Abbottb34aa862014-04-10 19:41:57 +01002322 struct comedi_buf_map *bm = NULL;
Ian Abbotte3647212019-06-25 12:26:59 +01002323 struct comedi_buf_page *buf;
David Schleefed9eccb2008-11-04 20:29:31 -08002324 unsigned long start = vma->vm_start;
2325 unsigned long size;
2326 int n_pages;
2327 int i;
Ian Abbotte3647212019-06-25 12:26:59 +01002328 int retval = 0;
Bernd Porr3ffab422011-11-08 21:23:03 +00002329
Ian Abbottb34aa862014-04-10 19:41:57 +01002330 /*
Michel Lespinassec1e8d7c2020-06-08 21:33:54 -07002331 * 'trylock' avoids circular dependency with current->mm->mmap_lock
Ian Abbottb34aa862014-04-10 19:41:57 +01002332 * and down-reading &dev->attach_lock should normally succeed without
2333 * contention unless the device is in the process of being attached
2334 * or detached.
2335 */
2336 if (!down_read_trylock(&dev->attach_lock))
2337 return -EAGAIN;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002338
David Schleefed9eccb2008-11-04 20:29:31 -08002339 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002340 dev_dbg(dev->class_dev, "no driver attached\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002341 retval = -ENODEV;
2342 goto done;
2343 }
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002344
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002345 if (vma->vm_flags & VM_WRITE)
Ian Abbott20f083c2014-11-04 18:09:00 +00002346 s = comedi_file_write_subdevice(file);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002347 else
Ian Abbott20f083c2014-11-04 18:09:00 +00002348 s = comedi_file_read_subdevice(file);
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002349 if (!s) {
David Schleefed9eccb2008-11-04 20:29:31 -08002350 retval = -EINVAL;
2351 goto done;
2352 }
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002353
David Schleefed9eccb2008-11-04 20:29:31 -08002354 async = s->async;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002355 if (!async) {
David Schleefed9eccb2008-11-04 20:29:31 -08002356 retval = -EINVAL;
2357 goto done;
2358 }
2359
2360 if (vma->vm_pgoff != 0) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002361 dev_dbg(dev->class_dev, "mmap() offset must be 0.\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002362 retval = -EINVAL;
2363 goto done;
2364 }
2365
2366 size = vma->vm_end - vma->vm_start;
2367 if (size > async->prealloc_bufsz) {
2368 retval = -EFAULT;
2369 goto done;
2370 }
Sandhya Bankar44b8c792016-03-06 12:35:29 +05302371 if (offset_in_page(size)) {
David Schleefed9eccb2008-11-04 20:29:31 -08002372 retval = -EFAULT;
2373 goto done;
2374 }
2375
sayli karnikec9d07542016-09-20 03:21:38 +05302376 n_pages = vma_pages(vma);
Ian Abbottb34aa862014-04-10 19:41:57 +01002377
2378 /* get reference to current buf map (if any) */
2379 bm = comedi_buf_map_from_subdev_get(s);
Ian Abbottaf93da32013-11-08 15:03:43 +00002380 if (!bm || n_pages > bm->n_pages) {
2381 retval = -EINVAL;
2382 goto done;
2383 }
Ian Abbotte3647212019-06-25 12:26:59 +01002384 if (bm->dma_dir != DMA_NONE) {
2385 /*
2386 * DMA buffer was allocated as a single block.
2387 * Address is in page_list[0].
2388 */
2389 buf = &bm->page_list[0];
2390 retval = dma_mmap_coherent(bm->dma_hw_dev, vma, buf->virt_addr,
2391 buf->dma_addr, n_pages * PAGE_SIZE);
2392 } else {
2393 for (i = 0; i < n_pages; ++i) {
2394 unsigned long pfn;
H Hartley Sweetena52840a2012-12-19 15:45:12 -07002395
Ian Abbotte3647212019-06-25 12:26:59 +01002396 buf = &bm->page_list[i];
2397 pfn = page_to_pfn(virt_to_page(buf->virt_addr));
2398 retval = remap_pfn_range(vma, start, pfn, PAGE_SIZE,
2399 PAGE_SHARED);
2400 if (retval)
2401 break;
2402
2403 start += PAGE_SIZE;
David Schleefed9eccb2008-11-04 20:29:31 -08002404 }
David Schleefed9eccb2008-11-04 20:29:31 -08002405 }
2406
Ian Abbotte3647212019-06-25 12:26:59 +01002407 if (retval == 0) {
2408 vma->vm_ops = &comedi_vm_ops;
2409 vma->vm_private_data = bm;
David Schleefed9eccb2008-11-04 20:29:31 -08002410
Ian Abbotte3647212019-06-25 12:26:59 +01002411 vma->vm_ops->open(vma);
2412 }
David Schleefed9eccb2008-11-04 20:29:31 -08002413
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002414done:
Ian Abbottb34aa862014-04-10 19:41:57 +01002415 up_read(&dev->attach_lock);
2416 comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
David Schleefed9eccb2008-11-04 20:29:31 -08002417 return retval;
2418}
2419
Al Viroafc9a422017-07-03 06:39:46 -04002420static __poll_t comedi_poll(struct file *file, poll_table *wait)
David Schleefed9eccb2008-11-04 20:29:31 -08002421{
Al Viroafc9a422017-07-03 06:39:46 -04002422 __poll_t mask = 0;
Ian Abbott20f083c2014-11-04 18:09:00 +00002423 struct comedi_file *cfp = file->private_data;
2424 struct comedi_device *dev = cfp->dev;
Ian Abbott322146d2015-10-09 12:26:47 +01002425 struct comedi_subdevice *s, *s_read;
Bernd Porr3ffab422011-11-08 21:23:03 +00002426
Ian Abbottd5eb3a72015-10-09 12:26:52 +01002427 down_read(&dev->attach_lock);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002428
David Schleefed9eccb2008-11-04 20:29:31 -08002429 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002430 dev_dbg(dev->class_dev, "no driver attached\n");
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002431 goto done;
David Schleefed9eccb2008-11-04 20:29:31 -08002432 }
2433
Ian Abbott20f083c2014-11-04 18:09:00 +00002434 s = comedi_file_read_subdevice(file);
Ian Abbott322146d2015-10-09 12:26:47 +01002435 s_read = s;
Ian Abbottcc400e12013-02-05 12:50:40 +00002436 if (s && s->async) {
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002437 poll_wait(file, &s->async->wait_head, wait);
Ian Abbott38342342015-10-09 12:26:51 +01002438 if (s->busy != file || !comedi_is_subdevice_running(s) ||
Ian Abbott662c7222014-10-30 12:42:31 +00002439 (s->async->cmd.flags & CMDF_WRITE) ||
Ian Abbotte9edef32014-05-06 13:12:09 +01002440 comedi_buf_read_n_available(s) > 0)
Linus Torvaldsa9a08842018-02-11 14:34:03 -08002441 mask |= EPOLLIN | EPOLLRDNORM;
David Schleefed9eccb2008-11-04 20:29:31 -08002442 }
2443
Ian Abbott20f083c2014-11-04 18:09:00 +00002444 s = comedi_file_write_subdevice(file);
Ian Abbottcc400e12013-02-05 12:50:40 +00002445 if (s && s->async) {
H Hartley Sweetenc39e0502014-10-31 12:04:28 -07002446 unsigned int bps = comedi_bytes_per_sample(s);
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002447
Ian Abbott322146d2015-10-09 12:26:47 +01002448 if (s != s_read)
2449 poll_wait(file, &s->async->wait_head, wait);
Ian Abbott38342342015-10-09 12:26:51 +01002450 if (s->busy != file || !comedi_is_subdevice_running(s) ||
Ian Abbott662c7222014-10-30 12:42:31 +00002451 !(s->async->cmd.flags & CMDF_WRITE) ||
Ian Abbottecf04ed2015-10-09 12:26:50 +01002452 comedi_buf_write_n_available(s) >= bps)
Linus Torvaldsa9a08842018-02-11 14:34:03 -08002453 mask |= EPOLLOUT | EPOLLWRNORM;
H Hartley Sweetenca081b12012-12-19 15:39:44 -07002454 }
2455
2456done:
Ian Abbottd5eb3a72015-10-09 12:26:52 +01002457 up_read(&dev->attach_lock);
David Schleefed9eccb2008-11-04 20:29:31 -08002458 return mask;
2459}
2460
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07002461static ssize_t comedi_write(struct file *file, const char __user *buf,
2462 size_t nbytes, loff_t *offset)
David Schleefed9eccb2008-11-04 20:29:31 -08002463{
Bill Pemberton34c43922009-03-16 22:05:14 -04002464 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04002465 struct comedi_async *async;
Ian Abbott84a185e2015-11-18 17:55:06 +00002466 unsigned int n, m;
2467 ssize_t count = 0;
2468 int retval = 0;
David Schleefed9eccb2008-11-04 20:29:31 -08002469 DECLARE_WAITQUEUE(wait, current);
Ian Abbott20f083c2014-11-04 18:09:00 +00002470 struct comedi_file *cfp = file->private_data;
2471 struct comedi_device *dev = cfp->dev;
Ian Abbott06181de2015-11-18 17:55:04 +00002472 bool become_nonbusy = false;
Ian Abbott9329f132013-11-08 15:03:30 +00002473 bool attach_locked;
2474 unsigned int old_detach_count;
Bernd Porr3ffab422011-11-08 21:23:03 +00002475
Ian Abbott9329f132013-11-08 15:03:30 +00002476 /* Protect against device detachment during operation. */
2477 down_read(&dev->attach_lock);
2478 attach_locked = true;
2479 old_detach_count = dev->detach_count;
2480
David Schleefed9eccb2008-11-04 20:29:31 -08002481 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002482 dev_dbg(dev->class_dev, "no driver attached\n");
Ian Abbott9329f132013-11-08 15:03:30 +00002483 retval = -ENODEV;
2484 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002485 }
2486
Ian Abbott20f083c2014-11-04 18:09:00 +00002487 s = comedi_file_write_subdevice(file);
Ian Abbott9329f132013-11-08 15:03:30 +00002488 if (!s || !s->async) {
2489 retval = -EIO;
2490 goto out;
2491 }
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002492
David Schleefed9eccb2008-11-04 20:29:31 -08002493 async = s->async;
Ian Abbott3318c7a2015-11-18 17:55:10 +00002494 if (s->busy != file || !(async->cmd.flags & CMDF_WRITE)) {
Ian Abbottf7398502014-10-30 12:42:30 +00002495 retval = -EINVAL;
2496 goto out;
2497 }
H Hartley Sweeten2714b012012-12-19 15:40:34 -07002498
David Schleefed9eccb2008-11-04 20:29:31 -08002499 add_wait_queue(&async->wait_head, &wait);
Ian Abbott06181de2015-11-18 17:55:04 +00002500 while (count == 0 && !retval) {
Leslie Kleind4d47892016-03-21 09:18:35 -04002501 unsigned int runflags;
Ian Abbott35a74752015-11-18 17:55:08 +00002502 unsigned int wp, n1, n2;
Ian Abbottb183a832015-03-27 15:13:01 +00002503
David Schleefed9eccb2008-11-04 20:29:31 -08002504 set_current_state(TASK_INTERRUPTIBLE);
2505
Ian Abbottb183a832015-03-27 15:13:01 +00002506 runflags = comedi_get_subdevice_runflags(s);
2507 if (!comedi_is_runflags_running(runflags)) {
Ian Abbott06181de2015-11-18 17:55:04 +00002508 if (comedi_is_runflags_in_error(runflags))
2509 retval = -EPIPE;
Ian Abbott28a60c42015-11-18 17:55:11 +00002510 if (retval || nbytes)
2511 become_nonbusy = true;
Ian Abbottd2611542010-05-19 17:22:41 +01002512 break;
2513 }
Ian Abbott28a60c42015-11-18 17:55:11 +00002514 if (nbytes == 0)
2515 break;
Ian Abbottd2611542010-05-19 17:22:41 +01002516
Ian Abbott591c5f82015-11-18 17:55:07 +00002517 /* Allocate all free buffer space. */
2518 comedi_buf_write_alloc(s, async->prealloc_bufsz);
2519 m = comedi_buf_write_n_allocated(s);
Ian Abbott591c5f82015-11-18 17:55:07 +00002520 n = min_t(size_t, m, nbytes);
David Schleefed9eccb2008-11-04 20:29:31 -08002521
2522 if (n == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08002523 if (file->f_flags & O_NONBLOCK) {
2524 retval = -EAGAIN;
2525 break;
2526 }
Federico Vaga6a9ce6b2011-10-29 09:47:39 +02002527 schedule();
David Schleefed9eccb2008-11-04 20:29:31 -08002528 if (signal_pending(current)) {
2529 retval = -ERESTARTSYS;
2530 break;
2531 }
Ian Abbott3318c7a2015-11-18 17:55:10 +00002532 if (s->busy != file ||
2533 !(async->cmd.flags & CMDF_WRITE)) {
Ian Abbottf7398502014-10-30 12:42:30 +00002534 retval = -EINVAL;
2535 break;
2536 }
David Schleefed9eccb2008-11-04 20:29:31 -08002537 continue;
2538 }
2539
Ian Abbottcef98862017-07-28 16:22:31 +01002540 set_current_state(TASK_RUNNING);
Ian Abbott35a74752015-11-18 17:55:08 +00002541 wp = async->buf_write_ptr;
2542 n1 = min(n, async->prealloc_bufsz - wp);
2543 n2 = n - n1;
2544 m = copy_from_user(async->prealloc_buf + wp, buf, n1);
2545 if (m)
2546 m += n2;
2547 else if (n2)
2548 m = copy_from_user(async->prealloc_buf, buf + n1, n2);
David Schleefed9eccb2008-11-04 20:29:31 -08002549 if (m) {
2550 n -= m;
2551 retval = -EFAULT;
2552 }
Ian Abbott940dd352014-05-06 13:12:05 +01002553 comedi_buf_write_free(s, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002554
2555 count += n;
2556 nbytes -= n;
2557
2558 buf += n;
Ian Abbott06181de2015-11-18 17:55:04 +00002559 }
2560 remove_wait_queue(&async->wait_head, &wait);
2561 set_current_state(TASK_RUNNING);
2562 if (become_nonbusy && count == 0) {
2563 struct comedi_subdevice *new_s;
2564
2565 /*
2566 * To avoid deadlock, cannot acquire dev->mutex
2567 * while dev->attach_lock is held.
2568 */
2569 up_read(&dev->attach_lock);
2570 attach_locked = false;
2571 mutex_lock(&dev->mutex);
2572 /*
2573 * Check device hasn't become detached behind our back.
2574 * Checking dev->detach_count is unchanged ought to be
2575 * sufficient (unless there have been 2**32 detaches in the
2576 * meantime!), but check the subdevice pointer as well just in
2577 * case.
Ian Abbotted65bba2015-11-18 17:55:05 +00002578 *
2579 * Also check the subdevice is still in a suitable state to
2580 * become non-busy in case it changed behind our back.
Ian Abbott06181de2015-11-18 17:55:04 +00002581 */
2582 new_s = comedi_file_write_subdevice(file);
2583 if (dev->attached && old_detach_count == dev->detach_count &&
Ian Abbotted65bba2015-11-18 17:55:05 +00002584 s == new_s && new_s->async == async && s->busy == file &&
2585 (async->cmd.flags & CMDF_WRITE) &&
2586 !comedi_is_subdevice_running(s))
Ian Abbott06181de2015-11-18 17:55:04 +00002587 do_become_nonbusy(dev, s);
2588 mutex_unlock(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002589 }
Ian Abbott9329f132013-11-08 15:03:30 +00002590out:
Ian Abbott9329f132013-11-08 15:03:30 +00002591 if (attach_locked)
2592 up_read(&dev->attach_lock);
David Schleefed9eccb2008-11-04 20:29:31 -08002593
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002594 return count ? count : retval;
David Schleefed9eccb2008-11-04 20:29:31 -08002595}
2596
Greg Kroah-Hartman92d01272010-05-03 16:32:28 -07002597static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07002598 loff_t *offset)
David Schleefed9eccb2008-11-04 20:29:31 -08002599{
Bill Pemberton34c43922009-03-16 22:05:14 -04002600 struct comedi_subdevice *s;
Bill Pembertond1636792009-03-16 22:05:20 -04002601 struct comedi_async *async;
Ian Abbott76e8e7d2015-10-12 17:21:23 +01002602 unsigned int n, m;
2603 ssize_t count = 0;
2604 int retval = 0;
David Schleefed9eccb2008-11-04 20:29:31 -08002605 DECLARE_WAITQUEUE(wait, current);
Ian Abbott20f083c2014-11-04 18:09:00 +00002606 struct comedi_file *cfp = file->private_data;
2607 struct comedi_device *dev = cfp->dev;
Ian Abbott45c2bc52013-11-08 15:03:31 +00002608 unsigned int old_detach_count;
2609 bool become_nonbusy = false;
2610 bool attach_locked;
Bernd Porr3ffab422011-11-08 21:23:03 +00002611
Ian Abbott45c2bc52013-11-08 15:03:31 +00002612 /* Protect against device detachment during operation. */
2613 down_read(&dev->attach_lock);
2614 attach_locked = true;
2615 old_detach_count = dev->detach_count;
2616
David Schleefed9eccb2008-11-04 20:29:31 -08002617 if (!dev->attached) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002618 dev_dbg(dev->class_dev, "no driver attached\n");
Ian Abbott45c2bc52013-11-08 15:03:31 +00002619 retval = -ENODEV;
2620 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002621 }
2622
Ian Abbott20f083c2014-11-04 18:09:00 +00002623 s = comedi_file_read_subdevice(file);
Ian Abbott45c2bc52013-11-08 15:03:31 +00002624 if (!s || !s->async) {
2625 retval = -EIO;
2626 goto out;
2627 }
H Hartley Sweeten5c87fef2012-12-19 15:40:08 -07002628
David Schleefed9eccb2008-11-04 20:29:31 -08002629 async = s->async;
Ian Abbott39582842015-10-12 17:21:28 +01002630 if (s->busy != file || (async->cmd.flags & CMDF_WRITE)) {
Ian Abbottf025ab92014-10-30 12:42:29 +00002631 retval = -EINVAL;
2632 goto out;
2633 }
David Schleefed9eccb2008-11-04 20:29:31 -08002634
2635 add_wait_queue(&async->wait_head, &wait);
Ian Abbott3c3bea22015-10-12 17:21:29 +01002636 while (count == 0 && !retval) {
Ian Abbott42ea9072015-10-12 17:21:25 +01002637 unsigned int rp, n1, n2;
2638
David Schleefed9eccb2008-11-04 20:29:31 -08002639 set_current_state(TASK_INTERRUPTIBLE);
2640
Ian Abbotte9edef32014-05-06 13:12:09 +01002641 m = comedi_buf_read_n_available(s);
Ian Abbott8ea93922015-10-12 17:21:24 +01002642 n = min_t(size_t, m, nbytes);
David Schleefed9eccb2008-11-04 20:29:31 -08002643
2644 if (n == 0) {
Ian Abbottb2073dc2016-03-29 10:49:04 +01002645 unsigned int runflags =
2646 comedi_get_subdevice_runflags(s);
Ian Abbottb183a832015-03-27 15:13:01 +00002647
2648 if (!comedi_is_runflags_running(runflags)) {
2649 if (comedi_is_runflags_in_error(runflags))
David Schleefed9eccb2008-11-04 20:29:31 -08002650 retval = -EPIPE;
Ian Abbott3c3bea22015-10-12 17:21:29 +01002651 if (retval || nbytes)
2652 become_nonbusy = true;
David Schleefed9eccb2008-11-04 20:29:31 -08002653 break;
2654 }
Ian Abbott3c3bea22015-10-12 17:21:29 +01002655 if (nbytes == 0)
2656 break;
David Schleefed9eccb2008-11-04 20:29:31 -08002657 if (file->f_flags & O_NONBLOCK) {
2658 retval = -EAGAIN;
2659 break;
2660 }
Federico Vaga6a9ce6b2011-10-29 09:47:39 +02002661 schedule();
David Schleefed9eccb2008-11-04 20:29:31 -08002662 if (signal_pending(current)) {
2663 retval = -ERESTARTSYS;
2664 break;
2665 }
Ian Abbott39582842015-10-12 17:21:28 +01002666 if (s->busy != file ||
2667 (async->cmd.flags & CMDF_WRITE)) {
Ian Abbottf025ab92014-10-30 12:42:29 +00002668 retval = -EINVAL;
2669 break;
2670 }
David Schleefed9eccb2008-11-04 20:29:31 -08002671 continue;
2672 }
Ian Abbottcef98862017-07-28 16:22:31 +01002673
2674 set_current_state(TASK_RUNNING);
Ian Abbott42ea9072015-10-12 17:21:25 +01002675 rp = async->buf_read_ptr;
2676 n1 = min(n, async->prealloc_bufsz - rp);
2677 n2 = n - n1;
2678 m = copy_to_user(buf, async->prealloc_buf + rp, n1);
2679 if (m)
2680 m += n2;
2681 else if (n2)
2682 m = copy_to_user(buf + n1, async->prealloc_buf, n2);
David Schleefed9eccb2008-11-04 20:29:31 -08002683 if (m) {
2684 n -= m;
2685 retval = -EFAULT;
2686 }
2687
Ian Abbottd13be552014-05-06 13:12:07 +01002688 comedi_buf_read_alloc(s, n);
Ian Abbottf1df8662014-05-06 13:12:08 +01002689 comedi_buf_read_free(s, n);
David Schleefed9eccb2008-11-04 20:29:31 -08002690
2691 count += n;
2692 nbytes -= n;
2693
2694 buf += n;
David Schleefed9eccb2008-11-04 20:29:31 -08002695 }
Ian Abbott45c2bc52013-11-08 15:03:31 +00002696 remove_wait_queue(&async->wait_head, &wait);
2697 set_current_state(TASK_RUNNING);
Ian Abbott970679b2015-10-12 17:21:20 +01002698 if (become_nonbusy && count == 0) {
Ian Abbott45c2bc52013-11-08 15:03:31 +00002699 struct comedi_subdevice *new_s;
2700
2701 /*
2702 * To avoid deadlock, cannot acquire dev->mutex
2703 * while dev->attach_lock is held.
2704 */
2705 up_read(&dev->attach_lock);
2706 attach_locked = false;
Ian Abbott4b18f082013-07-05 16:49:34 +01002707 mutex_lock(&dev->mutex);
Ian Abbott45c2bc52013-11-08 15:03:31 +00002708 /*
2709 * Check device hasn't become detached behind our back.
2710 * Checking dev->detach_count is unchanged ought to be
2711 * sufficient (unless there have been 2**32 detaches in the
2712 * meantime!), but check the subdevice pointer as well just in
2713 * case.
Ian Abbottfd060c82015-10-12 17:21:22 +01002714 *
2715 * Also check the subdevice is still in a suitable state to
2716 * become non-busy in case it changed behind our back.
Ian Abbott45c2bc52013-11-08 15:03:31 +00002717 */
Ian Abbott20f083c2014-11-04 18:09:00 +00002718 new_s = comedi_file_read_subdevice(file);
Ian Abbott45c2bc52013-11-08 15:03:31 +00002719 if (dev->attached && old_detach_count == dev->detach_count &&
Ian Abbottfd060c82015-10-12 17:21:22 +01002720 s == new_s && new_s->async == async && s->busy == file &&
2721 !(async->cmd.flags & CMDF_WRITE) &&
2722 !comedi_is_subdevice_running(s) &&
2723 comedi_buf_read_n_available(s) == 0)
2724 do_become_nonbusy(dev, s);
Ian Abbott4b18f082013-07-05 16:49:34 +01002725 mutex_unlock(&dev->mutex);
David Schleefed9eccb2008-11-04 20:29:31 -08002726 }
Ian Abbott45c2bc52013-11-08 15:03:31 +00002727out:
2728 if (attach_locked)
2729 up_read(&dev->attach_lock);
David Schleefed9eccb2008-11-04 20:29:31 -08002730
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002731 return count ? count : retval;
David Schleefed9eccb2008-11-04 20:29:31 -08002732}
2733
David Schleefed9eccb2008-11-04 20:29:31 -08002734static int comedi_open(struct inode *inode, struct file *file)
2735{
Leslie Kleind4d47892016-03-21 09:18:35 -04002736 const unsigned int minor = iminor(inode);
Ian Abbott20f083c2014-11-04 18:09:00 +00002737 struct comedi_file *cfp;
Ian Abbottfc406982013-11-08 15:03:34 +00002738 struct comedi_device *dev = comedi_dev_get_from_minor(minor);
2739 int rc;
Ian Abbott97920072009-02-09 16:51:38 +00002740
H Hartley Sweeten4da5fa92012-12-19 15:35:23 -07002741 if (!dev) {
H Hartley Sweeten272850f2013-11-26 10:21:11 -07002742 pr_debug("invalid minor number\n");
David Schleefed9eccb2008-11-04 20:29:31 -08002743 return -ENODEV;
2744 }
2745
Ian Abbott20f083c2014-11-04 18:09:00 +00002746 cfp = kzalloc(sizeof(*cfp), GFP_KERNEL);
Xiyu Yang332e0e12020-04-20 13:44:16 +08002747 if (!cfp) {
2748 comedi_dev_put(dev);
Ian Abbott20f083c2014-11-04 18:09:00 +00002749 return -ENOMEM;
Xiyu Yang332e0e12020-04-20 13:44:16 +08002750 }
Ian Abbott20f083c2014-11-04 18:09:00 +00002751
2752 cfp->dev = dev;
2753
David Schleefed9eccb2008-11-04 20:29:31 -08002754 mutex_lock(&dev->mutex);
Ian Abbott0e0d3112015-07-07 17:06:52 +01002755 if (!dev->attached && !capable(CAP_SYS_ADMIN)) {
2756 dev_dbg(dev->class_dev, "not attached and not CAP_SYS_ADMIN\n");
Ian Abbottfc406982013-11-08 15:03:34 +00002757 rc = -ENODEV;
2758 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002759 }
Ian Abbott1363e4f2013-12-11 14:51:03 +00002760 if (dev->attached && dev->use_count == 0) {
David Schleefed9eccb2008-11-04 20:29:31 -08002761 if (!try_module_get(dev->driver->module)) {
Santhosh Pai90e6f512015-06-29 10:44:03 +01002762 rc = -ENXIO;
Ian Abbottfc406982013-11-08 15:03:34 +00002763 goto out;
David Schleefed9eccb2008-11-04 20:29:31 -08002764 }
Ian Abbott1363e4f2013-12-11 14:51:03 +00002765 if (dev->open) {
2766 rc = dev->open(dev);
2767 if (rc < 0) {
2768 module_put(dev->driver->module);
2769 goto out;
2770 }
Ian Abbott3c17ba072010-05-19 14:10:00 +01002771 }
2772 }
David Schleefed9eccb2008-11-04 20:29:31 -08002773
2774 dev->use_count++;
Ian Abbott20f083c2014-11-04 18:09:00 +00002775 file->private_data = cfp;
2776 comedi_file_reset(file);
Ian Abbottfc406982013-11-08 15:03:34 +00002777 rc = 0;
David Schleefed9eccb2008-11-04 20:29:31 -08002778
Ian Abbottfc406982013-11-08 15:03:34 +00002779out:
David Schleefed9eccb2008-11-04 20:29:31 -08002780 mutex_unlock(&dev->mutex);
Ian Abbott20f083c2014-11-04 18:09:00 +00002781 if (rc) {
Ian Abbottfc406982013-11-08 15:03:34 +00002782 comedi_dev_put(dev);
Ian Abbott20f083c2014-11-04 18:09:00 +00002783 kfree(cfp);
2784 }
Ian Abbottfc406982013-11-08 15:03:34 +00002785 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -08002786}
2787
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002788static int comedi_fasync(int fd, struct file *file, int on)
2789{
Ian Abbott20f083c2014-11-04 18:09:00 +00002790 struct comedi_file *cfp = file->private_data;
2791 struct comedi_device *dev = cfp->dev;
H Hartley Sweeten2aae0072012-12-19 15:31:57 -07002792
2793 return fasync_helper(fd, file, on, &dev->async_queue);
2794}
2795
David Schleefed9eccb2008-11-04 20:29:31 -08002796static int comedi_close(struct inode *inode, struct file *file)
2797{
Ian Abbott20f083c2014-11-04 18:09:00 +00002798 struct comedi_file *cfp = file->private_data;
2799 struct comedi_device *dev = cfp->dev;
Bill Pemberton34c43922009-03-16 22:05:14 -04002800 struct comedi_subdevice *s = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08002801 int i;
Bernd Porr3ffab422011-11-08 21:23:03 +00002802
David Schleefed9eccb2008-11-04 20:29:31 -08002803 mutex_lock(&dev->mutex);
2804
2805 if (dev->subdevices) {
2806 for (i = 0; i < dev->n_subdevices; i++) {
H Hartley Sweetenb077f2c2012-09-05 18:20:58 -07002807 s = &dev->subdevices[i];
David Schleefed9eccb2008-11-04 20:29:31 -08002808
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002809 if (s->busy == file)
David Schleefed9eccb2008-11-04 20:29:31 -08002810 do_cancel(dev, s);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08002811 if (s->lock == file)
David Schleefed9eccb2008-11-04 20:29:31 -08002812 s->lock = NULL;
David Schleefed9eccb2008-11-04 20:29:31 -08002813 }
2814 }
Ian Abbott1363e4f2013-12-11 14:51:03 +00002815 if (dev->attached && dev->use_count == 1) {
2816 if (dev->close)
2817 dev->close(dev);
David Schleefed9eccb2008-11-04 20:29:31 -08002818 module_put(dev->driver->module);
Ian Abbott1363e4f2013-12-11 14:51:03 +00002819 }
David Schleefed9eccb2008-11-04 20:29:31 -08002820
2821 dev->use_count--;
2822
2823 mutex_unlock(&dev->mutex);
Ian Abbottfc406982013-11-08 15:03:34 +00002824 comedi_dev_put(dev);
Ian Abbott20f083c2014-11-04 18:09:00 +00002825 kfree(cfp);
David Schleefed9eccb2008-11-04 20:29:31 -08002826
David Schleefed9eccb2008-11-04 20:29:31 -08002827 return 0;
2828}
2829
Al Viroe0d0bf82020-04-25 18:19:30 -04002830#ifdef CONFIG_COMPAT
2831
2832#define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct)
2833#define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct)
2834/*
2835 * N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
2836 * It's too late to change it now, but it only affects the command number.
2837 */
2838#define COMEDI32_CMD _IOR(CIO, 9, struct comedi32_cmd_struct)
2839/*
2840 * N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
2841 * It's too late to change it now, but it only affects the command number.
2842 */
2843#define COMEDI32_CMDTEST _IOR(CIO, 10, struct comedi32_cmd_struct)
2844#define COMEDI32_INSNLIST _IOR(CIO, 11, struct comedi32_insnlist_struct)
2845#define COMEDI32_INSN _IOR(CIO, 12, struct comedi32_insn_struct)
2846
2847struct comedi32_chaninfo_struct {
2848 unsigned int subdev;
2849 compat_uptr_t maxdata_list; /* 32-bit 'unsigned int *' */
2850 compat_uptr_t flaglist; /* 32-bit 'unsigned int *' */
2851 compat_uptr_t rangelist; /* 32-bit 'unsigned int *' */
2852 unsigned int unused[4];
2853};
2854
2855struct comedi32_rangeinfo_struct {
2856 unsigned int range_type;
2857 compat_uptr_t range_ptr; /* 32-bit 'void *' */
2858};
2859
2860struct comedi32_cmd_struct {
2861 unsigned int subdev;
2862 unsigned int flags;
2863 unsigned int start_src;
2864 unsigned int start_arg;
2865 unsigned int scan_begin_src;
2866 unsigned int scan_begin_arg;
2867 unsigned int convert_src;
2868 unsigned int convert_arg;
2869 unsigned int scan_end_src;
2870 unsigned int scan_end_arg;
2871 unsigned int stop_src;
2872 unsigned int stop_arg;
2873 compat_uptr_t chanlist; /* 32-bit 'unsigned int *' */
2874 unsigned int chanlist_len;
2875 compat_uptr_t data; /* 32-bit 'short *' */
2876 unsigned int data_len;
2877};
2878
2879struct comedi32_insn_struct {
2880 unsigned int insn;
2881 unsigned int n;
2882 compat_uptr_t data; /* 32-bit 'unsigned int *' */
2883 unsigned int subdev;
2884 unsigned int chanspec;
2885 unsigned int unused[3];
2886};
2887
2888struct comedi32_insnlist_struct {
2889 unsigned int n_insns;
2890 compat_uptr_t insns; /* 32-bit 'struct comedi_insn *' */
2891};
2892
Al Viroe0d0bf82020-04-25 18:19:30 -04002893/* Handle 32-bit COMEDI_CHANINFO ioctl. */
2894static int compat_chaninfo(struct file *file, unsigned long arg)
2895{
Al Viro3fbfd222020-04-25 18:35:03 -04002896 struct comedi_file *cfp = file->private_data;
2897 struct comedi_device *dev = cfp->dev;
2898 struct comedi32_chaninfo_struct chaninfo32;
2899 struct comedi_chaninfo chaninfo;
Al Viroe0d0bf82020-04-25 18:19:30 -04002900 int err;
Al Viroe0d0bf82020-04-25 18:19:30 -04002901
Al Viro3fbfd222020-04-25 18:35:03 -04002902 if (copy_from_user(&chaninfo32, compat_ptr(arg), sizeof(chaninfo32)))
Al Viroe0d0bf82020-04-25 18:19:30 -04002903 return -EFAULT;
2904
Al Viro3fbfd222020-04-25 18:35:03 -04002905 memset(&chaninfo, 0, sizeof(chaninfo));
2906 chaninfo.subdev = chaninfo32.subdev;
2907 chaninfo.maxdata_list = compat_ptr(chaninfo32.maxdata_list);
2908 chaninfo.flaglist = compat_ptr(chaninfo32.flaglist);
2909 chaninfo.rangelist = compat_ptr(chaninfo32.rangelist);
Al Viroe0d0bf82020-04-25 18:19:30 -04002910
Al Viro3fbfd222020-04-25 18:35:03 -04002911 mutex_lock(&dev->mutex);
2912 err = do_chaninfo_ioctl(dev, &chaninfo);
2913 mutex_unlock(&dev->mutex);
2914 return err;
Al Viroe0d0bf82020-04-25 18:19:30 -04002915}
2916
2917/* Handle 32-bit COMEDI_RANGEINFO ioctl. */
2918static int compat_rangeinfo(struct file *file, unsigned long arg)
2919{
Al Viro38813872020-04-25 18:44:30 -04002920 struct comedi_file *cfp = file->private_data;
2921 struct comedi_device *dev = cfp->dev;
2922 struct comedi32_rangeinfo_struct rangeinfo32;
2923 struct comedi_rangeinfo rangeinfo;
Al Viroe0d0bf82020-04-25 18:19:30 -04002924 int err;
Al Viroe0d0bf82020-04-25 18:19:30 -04002925
Al Viro38813872020-04-25 18:44:30 -04002926 if (copy_from_user(&rangeinfo32, compat_ptr(arg), sizeof(rangeinfo32)))
Al Viroe0d0bf82020-04-25 18:19:30 -04002927 return -EFAULT;
Al Viro38813872020-04-25 18:44:30 -04002928 memset(&rangeinfo, 0, sizeof(rangeinfo));
2929 rangeinfo.range_type = rangeinfo32.range_type;
2930 rangeinfo.range_ptr = compat_ptr(rangeinfo32.range_ptr);
Al Viroe0d0bf82020-04-25 18:19:30 -04002931
Al Viro38813872020-04-25 18:44:30 -04002932 mutex_lock(&dev->mutex);
2933 err = do_rangeinfo_ioctl(dev, &rangeinfo);
2934 mutex_unlock(&dev->mutex);
2935 return err;
Al Viroe0d0bf82020-04-25 18:19:30 -04002936}
2937
2938/* Copy 32-bit cmd structure to native cmd structure. */
Al Virobac42fb2020-04-26 09:27:23 -04002939static int get_compat_cmd(struct comedi_cmd *cmd,
Al Viroe0d0bf82020-04-25 18:19:30 -04002940 struct comedi32_cmd_struct __user *cmd32)
2941{
Al Virobac42fb2020-04-26 09:27:23 -04002942 struct comedi32_cmd_struct v32;
Al Viroe0d0bf82020-04-25 18:19:30 -04002943
Al Virobac42fb2020-04-26 09:27:23 -04002944 if (copy_from_user(&v32, cmd32, sizeof(v32)))
Al Viroe0d0bf82020-04-25 18:19:30 -04002945 return -EFAULT;
2946
Al Virobac42fb2020-04-26 09:27:23 -04002947 cmd->subdev = v32.subdev;
2948 cmd->flags = v32.flags;
2949 cmd->start_src = v32.start_src;
2950 cmd->start_arg = v32.start_arg;
2951 cmd->scan_begin_src = v32.scan_begin_src;
2952 cmd->scan_begin_arg = v32.scan_begin_arg;
2953 cmd->convert_src = v32.convert_src;
2954 cmd->convert_arg = v32.convert_arg;
2955 cmd->scan_end_src = v32.scan_end_src;
2956 cmd->scan_end_arg = v32.scan_end_arg;
2957 cmd->stop_src = v32.stop_src;
2958 cmd->stop_arg = v32.stop_arg;
B K Karthik9d5d0412020-07-17 06:30:31 -04002959 cmd->chanlist = (unsigned int __force *)compat_ptr(v32.chanlist);
Al Virobac42fb2020-04-26 09:27:23 -04002960 cmd->chanlist_len = v32.chanlist_len;
2961 cmd->data = compat_ptr(v32.data);
2962 cmd->data_len = v32.data_len;
2963 return 0;
Al Viroe0d0bf82020-04-25 18:19:30 -04002964}
2965
2966/* Copy native cmd structure to 32-bit cmd structure. */
2967static int put_compat_cmd(struct comedi32_cmd_struct __user *cmd32,
Al Virobac42fb2020-04-26 09:27:23 -04002968 struct comedi_cmd *cmd)
Al Viroe0d0bf82020-04-25 18:19:30 -04002969{
Al Virobac42fb2020-04-26 09:27:23 -04002970 struct comedi32_cmd_struct v32;
Al Viroe0d0bf82020-04-25 18:19:30 -04002971
Al Virobac42fb2020-04-26 09:27:23 -04002972 memset(&v32, 0, sizeof(v32));
2973 v32.subdev = cmd->subdev;
2974 v32.flags = cmd->flags;
2975 v32.start_src = cmd->start_src;
2976 v32.start_arg = cmd->start_arg;
2977 v32.scan_begin_src = cmd->scan_begin_src;
2978 v32.scan_begin_arg = cmd->scan_begin_arg;
2979 v32.convert_src = cmd->convert_src;
2980 v32.convert_arg = cmd->convert_arg;
2981 v32.scan_end_src = cmd->scan_end_src;
2982 v32.scan_end_arg = cmd->scan_end_arg;
2983 v32.stop_src = cmd->stop_src;
2984 v32.stop_arg = cmd->stop_arg;
Al Viroe0d0bf82020-04-25 18:19:30 -04002985 /* Assume chanlist pointer is unchanged. */
B K Karthik9d5d0412020-07-17 06:30:31 -04002986 v32.chanlist = ptr_to_compat((unsigned int __user *)cmd->chanlist);
Al Virobac42fb2020-04-26 09:27:23 -04002987 v32.chanlist_len = cmd->chanlist_len;
2988 v32.data = ptr_to_compat(cmd->data);
2989 v32.data_len = cmd->data_len;
Dan Carpentercab36da2020-12-02 09:43:49 +03002990 if (copy_to_user(cmd32, &v32, sizeof(v32)))
2991 return -EFAULT;
2992 return 0;
Al Viroe0d0bf82020-04-25 18:19:30 -04002993}
2994
2995/* Handle 32-bit COMEDI_CMD ioctl. */
2996static int compat_cmd(struct file *file, unsigned long arg)
2997{
Al Virobac42fb2020-04-26 09:27:23 -04002998 struct comedi_file *cfp = file->private_data;
2999 struct comedi_device *dev = cfp->dev;
3000 struct comedi_cmd cmd;
3001 bool copy = false;
Al Viroe0d0bf82020-04-25 18:19:30 -04003002 int rc, err;
3003
Al Virobac42fb2020-04-26 09:27:23 -04003004 rc = get_compat_cmd(&cmd, compat_ptr(arg));
Al Viroe0d0bf82020-04-25 18:19:30 -04003005 if (rc)
3006 return rc;
3007
Al Virobac42fb2020-04-26 09:27:23 -04003008 mutex_lock(&dev->mutex);
3009 rc = do_cmd_ioctl(dev, &cmd, &copy, file);
3010 mutex_unlock(&dev->mutex);
3011 if (copy) {
Al Viroe0d0bf82020-04-25 18:19:30 -04003012 /* Special case: copy cmd back to user. */
Al Virobac42fb2020-04-26 09:27:23 -04003013 err = put_compat_cmd(compat_ptr(arg), &cmd);
Al Viroe0d0bf82020-04-25 18:19:30 -04003014 if (err)
3015 rc = err;
3016 }
Al Viroe0d0bf82020-04-25 18:19:30 -04003017 return rc;
3018}
3019
3020/* Handle 32-bit COMEDI_CMDTEST ioctl. */
3021static int compat_cmdtest(struct file *file, unsigned long arg)
3022{
Al Virobac42fb2020-04-26 09:27:23 -04003023 struct comedi_file *cfp = file->private_data;
3024 struct comedi_device *dev = cfp->dev;
3025 struct comedi_cmd cmd;
3026 bool copy = false;
Al Viroe0d0bf82020-04-25 18:19:30 -04003027 int rc, err;
3028
Al Virobac42fb2020-04-26 09:27:23 -04003029 rc = get_compat_cmd(&cmd, compat_ptr(arg));
Al Viroe0d0bf82020-04-25 18:19:30 -04003030 if (rc)
3031 return rc;
3032
Al Virobac42fb2020-04-26 09:27:23 -04003033 mutex_lock(&dev->mutex);
3034 rc = do_cmdtest_ioctl(dev, &cmd, &copy, file);
3035 mutex_unlock(&dev->mutex);
3036 if (copy) {
3037 err = put_compat_cmd(compat_ptr(arg), &cmd);
3038 if (err)
3039 rc = err;
3040 }
Al Viroe0d0bf82020-04-25 18:19:30 -04003041 return rc;
3042}
3043
3044/* Copy 32-bit insn structure to native insn structure. */
Al Viroaa332e62020-04-25 20:11:57 -04003045static int get_compat_insn(struct comedi_insn *insn,
3046 struct comedi32_insn_struct __user *insn32)
3047{
3048 struct comedi32_insn_struct v32;
3049
3050 /* Copy insn structure. Ignore the unused members. */
3051 if (copy_from_user(&v32, insn32, sizeof(v32)))
3052 return -EFAULT;
3053 memset(insn, 0, sizeof(*insn));
3054 insn->insn = v32.insn;
3055 insn->n = v32.n;
3056 insn->data = compat_ptr(v32.data);
3057 insn->subdev = v32.subdev;
3058 insn->chanspec = v32.chanspec;
3059 return 0;
3060}
3061
Al Viroe0d0bf82020-04-25 18:19:30 -04003062/* Handle 32-bit COMEDI_INSNLIST ioctl. */
3063static int compat_insnlist(struct file *file, unsigned long arg)
3064{
Al Virob8d47d82020-04-25 20:33:04 -04003065 struct comedi_file *cfp = file->private_data;
3066 struct comedi_device *dev = cfp->dev;
3067 struct comedi32_insnlist_struct insnlist32;
Al Viroe0d0bf82020-04-25 18:19:30 -04003068 struct comedi32_insn_struct __user *insn32;
Al Virob8d47d82020-04-25 20:33:04 -04003069 struct comedi_insn *insns;
3070 unsigned int n;
3071 int rc;
Al Viroe0d0bf82020-04-25 18:19:30 -04003072
Al Virob8d47d82020-04-25 20:33:04 -04003073 if (copy_from_user(&insnlist32, compat_ptr(arg), sizeof(insnlist32)))
Al Viroe0d0bf82020-04-25 18:19:30 -04003074 return -EFAULT;
3075
Al Virob8d47d82020-04-25 20:33:04 -04003076 insns = kcalloc(insnlist32.n_insns, sizeof(*insns), GFP_KERNEL);
3077 if (!insns)
3078 return -ENOMEM;
Al Viroe0d0bf82020-04-25 18:19:30 -04003079
3080 /* Copy insn structures. */
Al Virob8d47d82020-04-25 20:33:04 -04003081 insn32 = compat_ptr(insnlist32.insns);
3082 for (n = 0; n < insnlist32.n_insns; n++) {
3083 rc = get_compat_insn(insns + n, insn32 + n);
3084 if (rc) {
3085 kfree(insns);
Al Viroe0d0bf82020-04-25 18:19:30 -04003086 return rc;
Al Virob8d47d82020-04-25 20:33:04 -04003087 }
Al Viroe0d0bf82020-04-25 18:19:30 -04003088 }
3089
Al Virob8d47d82020-04-25 20:33:04 -04003090 mutex_lock(&dev->mutex);
3091 rc = do_insnlist_ioctl(dev, insns, insnlist32.n_insns, file);
3092 mutex_unlock(&dev->mutex);
Ian Abbottbb509a62021-09-16 15:50:23 +01003093 kfree(insns);
Al Virob8d47d82020-04-25 20:33:04 -04003094 return rc;
Al Viroe0d0bf82020-04-25 18:19:30 -04003095}
3096
3097/* Handle 32-bit COMEDI_INSN ioctl. */
3098static int compat_insn(struct file *file, unsigned long arg)
3099{
Al Viroaa332e62020-04-25 20:11:57 -04003100 struct comedi_file *cfp = file->private_data;
3101 struct comedi_device *dev = cfp->dev;
3102 struct comedi_insn insn;
Al Viroe0d0bf82020-04-25 18:19:30 -04003103 int rc;
3104
Al Viroaa332e62020-04-25 20:11:57 -04003105 rc = get_compat_insn(&insn, (void __user *)arg);
Al Viroe0d0bf82020-04-25 18:19:30 -04003106 if (rc)
3107 return rc;
3108
Al Viroaa332e62020-04-25 20:11:57 -04003109 mutex_lock(&dev->mutex);
3110 rc = do_insn_ioctl(dev, &insn, file);
3111 mutex_unlock(&dev->mutex);
3112 return rc;
Al Viroe0d0bf82020-04-25 18:19:30 -04003113}
3114
3115/*
3116 * compat_ioctl file operation.
3117 *
3118 * Returns -ENOIOCTLCMD for unrecognised ioctl codes.
3119 */
3120static long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3121{
3122 int rc;
3123
3124 switch (cmd) {
3125 case COMEDI_DEVCONFIG:
3126 case COMEDI_DEVINFO:
3127 case COMEDI_SUBDINFO:
3128 case COMEDI_BUFCONFIG:
3129 case COMEDI_BUFINFO:
3130 /* Just need to translate the pointer argument. */
3131 arg = (unsigned long)compat_ptr(arg);
Al Viro5c6a8742020-04-25 18:23:17 -04003132 rc = comedi_unlocked_ioctl(file, cmd, arg);
Al Viroe0d0bf82020-04-25 18:19:30 -04003133 break;
3134 case COMEDI_LOCK:
3135 case COMEDI_UNLOCK:
3136 case COMEDI_CANCEL:
3137 case COMEDI_POLL:
3138 case COMEDI_SETRSUBD:
3139 case COMEDI_SETWSUBD:
3140 /* No translation needed. */
Al Viro5c6a8742020-04-25 18:23:17 -04003141 rc = comedi_unlocked_ioctl(file, cmd, arg);
Al Viroe0d0bf82020-04-25 18:19:30 -04003142 break;
3143 case COMEDI32_CHANINFO:
3144 rc = compat_chaninfo(file, arg);
3145 break;
3146 case COMEDI32_RANGEINFO:
3147 rc = compat_rangeinfo(file, arg);
3148 break;
3149 case COMEDI32_CMD:
3150 rc = compat_cmd(file, arg);
3151 break;
3152 case COMEDI32_CMDTEST:
3153 rc = compat_cmdtest(file, arg);
3154 break;
3155 case COMEDI32_INSNLIST:
3156 rc = compat_insnlist(file, arg);
3157 break;
3158 case COMEDI32_INSN:
3159 rc = compat_insn(file, arg);
3160 break;
3161 default:
3162 rc = -ENOIOCTLCMD;
3163 break;
3164 }
3165 return rc;
3166}
3167#else
3168#define comedi_compat_ioctl NULL
3169#endif
3170
Ian Abbott8cb8aad2012-06-19 10:17:43 +01003171static const struct file_operations comedi_fops = {
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05303172 .owner = THIS_MODULE,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05303173 .unlocked_ioctl = comedi_unlocked_ioctl,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05303174 .compat_ioctl = comedi_compat_ioctl,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +05303175 .open = comedi_open,
3176 .release = comedi_close,
3177 .read = comedi_read,
3178 .write = comedi_write,
3179 .mmap = comedi_mmap,
3180 .poll = comedi_poll,
3181 .fasync = comedi_fasync,
Arnd Bergmann6038f372010-08-15 18:52:59 +02003182 .llseek = noop_llseek,
David Schleefed9eccb2008-11-04 20:29:31 -08003183};
3184
Ian Abbottdd630cd2015-01-28 18:41:46 +00003185/**
Ian Abbotta3e39942015-09-23 16:33:27 +01003186 * comedi_event() - Handle events for asynchronous COMEDI command
3187 * @dev: COMEDI device.
3188 * @s: COMEDI subdevice.
3189 * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held.
Ian Abbottdd630cd2015-01-28 18:41:46 +00003190 *
Ian Abbotta3e39942015-09-23 16:33:27 +01003191 * If an asynchronous COMEDI command is active on the subdevice, process
3192 * any %COMEDI_CB_... event flags that have been set, usually by an
Ian Abbottdd630cd2015-01-28 18:41:46 +00003193 * interrupt handler. These may change the run state of the asynchronous
Ian Abbotta3e39942015-09-23 16:33:27 +01003194 * command, wake a task, and/or send a %SIGIO signal.
Ian Abbottdd630cd2015-01-28 18:41:46 +00003195 */
Bill Pemberton34c43922009-03-16 22:05:14 -04003196void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08003197{
Bill Pembertond1636792009-03-16 22:05:20 -04003198 struct comedi_async *async = s->async;
Ian Abbottef4b4b22015-03-27 15:13:06 +00003199 unsigned int events;
3200 int si_code = 0;
3201 unsigned long flags;
David Schleefed9eccb2008-11-04 20:29:31 -08003202
Ian Abbottef4b4b22015-03-27 15:13:06 +00003203 spin_lock_irqsave(&s->spin_lock, flags);
3204
3205 events = async->events;
Ian Abbott922d9ce2015-03-27 15:13:04 +00003206 async->events = 0;
Ian Abbottef4b4b22015-03-27 15:13:06 +00003207 if (!__comedi_is_subdevice_running(s)) {
3208 spin_unlock_irqrestore(&s->spin_lock, flags);
David Schleefed9eccb2008-11-04 20:29:31 -08003209 return;
Ian Abbottef4b4b22015-03-27 15:13:06 +00003210 }
David Schleefed9eccb2008-11-04 20:29:31 -08003211
Ian Abbott922d9ce2015-03-27 15:13:04 +00003212 if (events & COMEDI_CB_CANCEL_MASK)
Ian Abbottef4b4b22015-03-27 15:13:06 +00003213 __comedi_clear_subdevice_runflags(s, COMEDI_SRF_RUNNING);
H Hartley Sweeten781f9332014-10-13 09:56:08 -07003214
3215 /*
Ian Abbottef4b4b22015-03-27 15:13:06 +00003216 * Remember if an error event has occurred, so an error can be
3217 * returned the next time the user does a read() or write().
H Hartley Sweeten781f9332014-10-13 09:56:08 -07003218 */
Ian Abbottef4b4b22015-03-27 15:13:06 +00003219 if (events & COMEDI_CB_ERROR_MASK)
3220 __comedi_set_subdevice_runflags(s, COMEDI_SRF_ERROR);
David Schleefed9eccb2008-11-04 20:29:31 -08003221
Ian Abbott922d9ce2015-03-27 15:13:04 +00003222 if (async->cb_mask & events) {
Ian Abbottc265be02013-11-08 15:03:22 +00003223 wake_up_interruptible(&async->wait_head);
Ian Abbottaa331222015-03-27 15:13:05 +00003224 si_code = async->cmd.flags & CMDF_WRITE ? POLL_OUT : POLL_IN;
David Schleefed9eccb2008-11-04 20:29:31 -08003225 }
Ian Abbottef4b4b22015-03-27 15:13:06 +00003226
3227 spin_unlock_irqrestore(&s->spin_lock, flags);
3228
3229 if (si_code)
3230 kill_fasync(&dev->async_queue, SIGIO, si_code);
David Schleefed9eccb2008-11-04 20:29:31 -08003231}
H Hartley Sweeten5660e742013-04-12 10:11:54 -07003232EXPORT_SYMBOL_GPL(comedi_event);
David Schleefed9eccb2008-11-04 20:29:31 -08003233
Ian Abbott07778392013-04-04 14:58:51 +01003234/* Note: the ->mutex is pre-locked on successful return */
Ian Abbott7638ffc2013-04-04 14:58:50 +01003235struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
David Schleefed9eccb2008-11-04 20:29:31 -08003236{
Ian Abbott7638ffc2013-04-04 14:58:50 +01003237 struct comedi_device *dev;
Bill Pemberton0bfbbe82009-03-16 22:05:36 -04003238 struct device *csdev;
Leslie Kleind4d47892016-03-21 09:18:35 -04003239 unsigned int i;
David Schleefed9eccb2008-11-04 20:29:31 -08003240
H Hartley Sweeten36efbac2014-07-18 14:28:14 -07003241 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -07003242 if (!dev)
Ian Abbott7638ffc2013-04-04 14:58:50 +01003243 return ERR_PTR(-ENOMEM);
Ian Abbott7638ffc2013-04-04 14:58:50 +01003244 comedi_device_init(dev);
Ian Abbottdb2e3482013-04-04 14:59:00 +01003245 comedi_set_hw_dev(dev, hardware_device);
Ian Abbott07778392013-04-04 14:58:51 +01003246 mutex_lock(&dev->mutex);
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003247 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbott38b97222013-04-04 14:58:52 +01003248 for (i = hardware_device ? comedi_num_legacy_minors : 0;
3249 i < COMEDI_NUM_BOARD_MINORS; ++i) {
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -07003250 if (!comedi_board_minor_table[i]) {
Ian Abbottcb6b79d2013-04-04 14:59:16 +01003251 comedi_board_minor_table[i] = dev;
David Schleefed9eccb2008-11-04 20:29:31 -08003252 break;
3253 }
3254 }
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003255 mutex_unlock(&comedi_board_minor_table_lock);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08003256 if (i == COMEDI_NUM_BOARD_MINORS) {
Ian Abbott07778392013-04-04 14:58:51 +01003257 mutex_unlock(&dev->mutex);
Ian Abbott7638ffc2013-04-04 14:58:50 +01003258 comedi_device_cleanup(dev);
Ian Abbott5b13ed92013-11-08 15:03:32 +00003259 comedi_dev_put(dev);
Haneen Mohammeda112eab2015-03-17 08:33:51 +03003260 dev_err(hardware_device,
3261 "ran out of minor numbers for board device files\n");
Ian Abbott7638ffc2013-04-04 14:58:50 +01003262 return ERR_PTR(-EBUSY);
David Schleefed9eccb2008-11-04 20:29:31 -08003263 }
Ian Abbott7638ffc2013-04-04 14:58:50 +01003264 dev->minor = i;
Pavel Roskin0435f932011-07-06 10:15:44 -04003265 csdev = device_create(comedi_class, hardware_device,
3266 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08003267 if (!IS_ERR(csdev))
Ian Abbott8f988d82013-12-11 14:51:02 +00003268 dev->class_dev = get_device(csdev);
H Hartley Sweetena5011a22012-05-09 09:20:08 -07003269
Ian Abbott07778392013-04-04 14:58:51 +01003270 /* Note: dev->mutex needs to be unlocked by the caller. */
Ian Abbott7638ffc2013-04-04 14:58:50 +01003271 return dev;
David Schleefed9eccb2008-11-04 20:29:31 -08003272}
3273
Ian Abbott3346b792013-04-04 14:58:47 +01003274void comedi_release_hardware_device(struct device *hardware_device)
Ian Abbottc43435d2012-03-30 17:14:58 +01003275{
3276 int minor;
Ian Abbottcb6b79d2013-04-04 14:59:16 +01003277 struct comedi_device *dev;
Ian Abbottc43435d2012-03-30 17:14:58 +01003278
Ian Abbott38b97222013-04-04 14:58:52 +01003279 for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
3280 minor++) {
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003281 mutex_lock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01003282 dev = comedi_board_minor_table[minor];
3283 if (dev && dev->hw_dev == hardware_device) {
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003284 comedi_board_minor_table[minor] = NULL;
3285 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottcb6b79d2013-04-04 14:59:16 +01003286 comedi_free_board_dev(dev);
Ian Abbott3346b792013-04-04 14:58:47 +01003287 break;
Ian Abbottc43435d2012-03-30 17:14:58 +01003288 }
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003289 mutex_unlock(&comedi_board_minor_table_lock);
Ian Abbottc43435d2012-03-30 17:14:58 +01003290 }
Ian Abbottc43435d2012-03-30 17:14:58 +01003291}
3292
Ian Abbottf65cc542013-02-01 10:20:30 +00003293int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08003294{
Ian Abbottf65cc542013-02-01 10:20:30 +00003295 struct comedi_device *dev = s->device;
Bill Pemberton0bfbbe82009-03-16 22:05:36 -04003296 struct device *csdev;
Leslie Kleind4d47892016-03-21 09:18:35 -04003297 unsigned int i;
David Schleefed9eccb2008-11-04 20:29:31 -08003298
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003299 mutex_lock(&comedi_subdevice_minor_table_lock);
3300 for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -07003301 if (!comedi_subdevice_minor_table[i]) {
Ian Abbottbd5b4172013-04-04 14:59:15 +01003302 comedi_subdevice_minor_table[i] = s;
David Schleefed9eccb2008-11-04 20:29:31 -08003303 break;
3304 }
3305 }
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003306 mutex_unlock(&comedi_subdevice_minor_table_lock);
3307 if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
Haneen Mohammeda112eab2015-03-17 08:33:51 +03003308 dev_err(dev->class_dev,
3309 "ran out of minor numbers for subdevice files\n");
David Schleefed9eccb2008-11-04 20:29:31 -08003310 return -EBUSY;
3311 }
Ian Abbott5b7dba1b2013-04-04 14:59:04 +01003312 i += COMEDI_NUM_BOARD_MINORS;
David Schleefed9eccb2008-11-04 20:29:31 -08003313 s->minor = i;
Pavel Roskin0435f932011-07-06 10:15:44 -04003314 csdev = device_create(comedi_class, dev->class_dev,
3315 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
H Hartley Sweeten90a35c12012-12-19 17:27:02 -07003316 dev->minor, s->index);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08003317 if (!IS_ERR(csdev))
David Schleefed9eccb2008-11-04 20:29:31 -08003318 s->class_dev = csdev;
H Hartley Sweetena5011a22012-05-09 09:20:08 -07003319
Ian Abbottda718542013-02-07 16:03:00 +00003320 return 0;
David Schleefed9eccb2008-11-04 20:29:31 -08003321}
3322
Bill Pemberton34c43922009-03-16 22:05:14 -04003323void comedi_free_subdevice_minor(struct comedi_subdevice *s)
David Schleefed9eccb2008-11-04 20:29:31 -08003324{
Ian Abbott0fcc9d42013-04-04 14:59:13 +01003325 unsigned int i;
David Schleefed9eccb2008-11-04 20:29:31 -08003326
H Hartley Sweeten88cc30c2015-03-04 12:15:28 -07003327 if (!s)
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08003328 return;
H Hartley Sweeten5104a892015-08-10 13:14:01 -07003329 if (s->minor < COMEDI_NUM_BOARD_MINORS ||
3330 s->minor >= COMEDI_NUM_MINORS)
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08003331 return;
David Schleefed9eccb2008-11-04 20:29:31 -08003332
Ian Abbott0fcc9d42013-04-04 14:59:13 +01003333 i = s->minor - COMEDI_NUM_BOARD_MINORS;
3334 mutex_lock(&comedi_subdevice_minor_table_lock);
Ian Abbottbd5b4172013-04-04 14:59:15 +01003335 if (s == comedi_subdevice_minor_table[i])
3336 comedi_subdevice_minor_table[i] = NULL;
Ian Abbott0fcc9d42013-04-04 14:59:13 +01003337 mutex_unlock(&comedi_subdevice_minor_table_lock);
Greg Kroah-Hartman476b8472008-11-13 17:05:58 -08003338 if (s->class_dev) {
David Schleefed9eccb2008-11-04 20:29:31 -08003339 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
3340 s->class_dev = NULL;
3341 }
David Schleefed9eccb2008-11-04 20:29:31 -08003342}
H Hartley Sweetena5787822012-12-19 15:40:59 -07003343
Ian Abbott682b9112013-01-28 17:07:39 +00003344static void comedi_cleanup_board_minors(void)
H Hartley Sweeten76cca892012-12-19 15:41:42 -07003345{
H Hartley Sweeten2be8ae52015-08-10 13:13:59 -07003346 struct comedi_device *dev;
Leslie Kleind4d47892016-03-21 09:18:35 -04003347 unsigned int i;
H Hartley Sweeten76cca892012-12-19 15:41:42 -07003348
H Hartley Sweeten2be8ae52015-08-10 13:13:59 -07003349 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
3350 dev = comedi_clear_board_minor(i);
3351 comedi_free_board_dev(dev);
3352 }
H Hartley Sweeten76cca892012-12-19 15:41:42 -07003353}
3354
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003355static int __init comedi_init(void)
3356{
3357 int i;
3358 int retval;
3359
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07003360 pr_info("version " COMEDI_RELEASE " - http://www.comedi.org\n");
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003361
Cheah Kok Cheongd1d78d22017-03-08 02:13:58 +08003362 if (comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07003363 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 -07003364 COMEDI_NUM_BOARD_MINORS);
3365 return -EINVAL;
3366 }
3367
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003368 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
3369 COMEDI_NUM_MINORS, "comedi");
3370 if (retval)
Ian Abbott125178d2017-06-16 19:35:35 +01003371 return retval;
3372
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003373 cdev_init(&comedi_cdev, &comedi_fops);
3374 comedi_cdev.owner = THIS_MODULE;
Anton Protopopova5bde3a2014-07-09 09:12:37 +04003375
3376 retval = kobject_set_name(&comedi_cdev.kobj, "comedi");
Ian Abbott125178d2017-06-16 19:35:35 +01003377 if (retval)
3378 goto out_unregister_chrdev_region;
Anton Protopopova5bde3a2014-07-09 09:12:37 +04003379
Ian Abbott125178d2017-06-16 19:35:35 +01003380 retval = cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0),
3381 COMEDI_NUM_MINORS);
3382 if (retval)
3383 goto out_unregister_chrdev_region;
3384
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003385 comedi_class = class_create(THIS_MODULE, "comedi");
3386 if (IS_ERR(comedi_class)) {
Ian Abbott125178d2017-06-16 19:35:35 +01003387 retval = PTR_ERR(comedi_class);
H Hartley Sweetenc2ad0782014-07-17 12:27:32 -07003388 pr_err("failed to create class\n");
Ian Abbott125178d2017-06-16 19:35:35 +01003389 goto out_cdev_del;
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003390 }
3391
Greg Kroah-Hartmane56341a2013-07-24 15:05:25 -07003392 comedi_class->dev_groups = comedi_dev_groups;
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003393
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003394 /* create devices files for legacy/manual use */
3395 for (i = 0; i < comedi_num_legacy_minors; i++) {
Ian Abbott7638ffc2013-04-04 14:58:50 +01003396 struct comedi_device *dev;
Raghavendra Ganiga4bac39f2014-05-01 13:53:12 +05303397
Ian Abbott7638ffc2013-04-04 14:58:50 +01003398 dev = comedi_alloc_board_minor(NULL);
3399 if (IS_ERR(dev)) {
Ian Abbott125178d2017-06-16 19:35:35 +01003400 retval = PTR_ERR(dev);
3401 goto out_cleanup_board_minors;
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003402 }
Kinka Huangcb3aada2014-07-15 23:11:02 +08003403 /* comedi_alloc_board_minor() locked the mutex */
Ian Abbott77c21b62019-04-17 15:39:29 +01003404 lockdep_assert_held(&dev->mutex);
Kinka Huangcb3aada2014-07-15 23:11:02 +08003405 mutex_unlock(&dev->mutex);
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003406 }
3407
Cheah Kok Cheongbf279ec2016-12-30 19:25:52 +08003408 /* XXX requires /proc interface */
3409 comedi_proc_init();
3410
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003411 return 0;
Ian Abbott125178d2017-06-16 19:35:35 +01003412
3413out_cleanup_board_minors:
3414 comedi_cleanup_board_minors();
3415 class_destroy(comedi_class);
3416out_cdev_del:
3417 cdev_del(&comedi_cdev);
3418out_unregister_chrdev_region:
3419 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
3420 return retval;
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003421}
3422module_init(comedi_init);
3423
3424static void __exit comedi_cleanup(void)
3425{
Ian Abbott682b9112013-01-28 17:07:39 +00003426 comedi_cleanup_board_minors();
H Hartley Sweeten91fa0b02012-12-19 15:41:19 -07003427 class_destroy(comedi_class);
3428 cdev_del(&comedi_cdev);
3429 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
3430
3431 comedi_proc_cleanup();
3432}
3433module_exit(comedi_cleanup);
3434
Alexander A. Klimov13d8b1f2020-07-23 21:40:53 +02003435MODULE_AUTHOR("https://www.comedi.org");
H Hartley Sweetena5787822012-12-19 15:40:59 -07003436MODULE_DESCRIPTION("Comedi core module");
3437MODULE_LICENSE("GPL");