staging: comedi: comedi_fops: remove BUG_ON() in comedi_free_subdevice_minor()
[deliverable/linux.git] / drivers / staging / comedi / comedi_fops.c
CommitLineData
ed9eccbe 1/*
f6fef5df
IA
2 * comedi/comedi_fops.c
3 * comedi kernel module
4 *
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
ed9eccbe 18
c2ad078b
HS
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
ed9eccbe
DS
21#include "comedi_compat32.h"
22
23#include <linux/module.h>
24#include <linux/errno.h>
25#include <linux/kernel.h>
26#include <linux/sched.h>
27#include <linux/fcntl.h>
28#include <linux/delay.h>
ed9eccbe
DS
29#include <linux/mm.h>
30#include <linux/slab.h>
31#include <linux/kmod.h>
32#include <linux/poll.h>
33#include <linux/init.h>
34#include <linux/device.h>
35#include <linux/vmalloc.h>
36#include <linux/fs.h>
37#include "comedidev.h"
38#include <linux/cdev.h>
883db3d9 39#include <linux/stat.h>
ed9eccbe 40
476b8477
GKH
41#include <linux/io.h>
42#include <linux/uaccess.h>
ed9eccbe 43
3a5fa275 44#include "comedi_internal.h"
ed9eccbe 45
eb340aca
IA
46/**
47 * comedi_subdevice "runflags"
48 * @COMEDI_SRF_RT: DEPRECATED: command is running real-time
49 * @COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred
50 * since the last command was started
51 * @COMEDI_SRF_RUNNING: command is running
52 * @COMEDI_SRF_FREE_SPRIV: free s->private on detach
53 *
54 * @COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy"
55 */
56#define COMEDI_SRF_RT BIT(1)
57#define COMEDI_SRF_ERROR BIT(2)
58#define COMEDI_SRF_RUNNING BIT(27)
59#define COMEDI_SRF_FREE_SPRIV BIT(31)
60
61#define COMEDI_SRF_BUSY_MASK (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING)
62
20f083c0
IA
63/**
64 * struct comedi_file - per-file private data for comedi device
65 * @dev: comedi_device struct
66 * @read_subdev: current "read" subdevice
67 * @write_subdev: current "write" subdevice
68 * @last_detach_count: last known detach count
69 * @last_attached: last known attached/detached state
70 */
71struct comedi_file {
72 struct comedi_device *dev;
73 struct comedi_subdevice *read_subdev;
74 struct comedi_subdevice *write_subdev;
75 unsigned int last_detach_count;
76 bool last_attached:1;
77};
78
eda56825 79#define COMEDI_NUM_MINORS 0x100
5b7dba1b
IA
80#define COMEDI_NUM_SUBDEVICE_MINORS \
81 (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
eda56825 82
92d0127c 83static int comedi_num_legacy_minors;
4d7df821
IA
84module_param(comedi_num_legacy_minors, int, S_IRUGO);
85MODULE_PARM_DESC(comedi_num_legacy_minors,
86 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
87 );
88
234bb3c6 89unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
4d7df821
IA
90module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
91MODULE_PARM_DESC(comedi_default_buf_size_kb,
92 "default asynchronous buffer size in KiB (default "
234bb3c6 93 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
4d7df821 94
234bb3c6
IA
95unsigned int comedi_default_buf_maxsize_kb
96 = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
4d7df821
IA
97module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
98MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
99 "default maximum size of asynchronous buffer in KiB (default "
234bb3c6 100 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
1dd33ab8 101
5b7dba1b 102static DEFINE_MUTEX(comedi_board_minor_table_lock);
cb6b79de 103static struct comedi_device
5b7dba1b
IA
104*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
105
106static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
107/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
bd5b4173 108static struct comedi_subdevice
5b7dba1b 109*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
476b8477 110
d9740a03
IA
111static struct class *comedi_class;
112static struct cdev comedi_cdev;
113
114static void comedi_device_init(struct comedi_device *dev)
115{
5b13ed94 116 kref_init(&dev->refcount);
d9740a03
IA
117 spin_lock_init(&dev->spinlock);
118 mutex_init(&dev->mutex);
2f3fdcd7 119 init_rwsem(&dev->attach_lock);
d9740a03
IA
120 dev->minor = -1;
121}
122
5b13ed94
IA
123static void comedi_dev_kref_release(struct kref *kref)
124{
125 struct comedi_device *dev =
126 container_of(kref, struct comedi_device, refcount);
127
128 mutex_destroy(&dev->mutex);
8f988d87 129 put_device(dev->class_dev);
5b13ed94
IA
130 kfree(dev);
131}
132
dd630cde
IA
133/**
134 * comedi_dev_put - release a use of a comedi device structure
135 * @dev: comedi_device struct
136 *
137 * Must be called when a user of a comedi device is finished with it.
138 * When the last user of the comedi device calls this function, the
139 * comedi device is destroyed.
140 *
141 * Return 1 if the comedi device is destroyed by this call or dev is
142 * NULL, otherwise return 0. Callers must not assume the comedi
143 * device is still valid if this function returns 0.
144 */
5b13ed94
IA
145int comedi_dev_put(struct comedi_device *dev)
146{
147 if (dev)
148 return kref_put(&dev->refcount, comedi_dev_kref_release);
149 return 1;
150}
b449c1ca
IA
151EXPORT_SYMBOL_GPL(comedi_dev_put);
152
153static struct comedi_device *comedi_dev_get(struct comedi_device *dev)
154{
155 if (dev)
156 kref_get(&dev->refcount);
157 return dev;
158}
5b13ed94 159
d9740a03
IA
160static void comedi_device_cleanup(struct comedi_device *dev)
161{
162 struct module *driver_module = NULL;
163
88cc30cf 164 if (!dev)
d9740a03
IA
165 return;
166 mutex_lock(&dev->mutex);
167 if (dev->attached)
168 driver_module = dev->driver->module;
169 comedi_device_detach(dev);
1363e4fb
IA
170 if (driver_module && dev->use_count)
171 module_put(driver_module);
d9740a03 172 mutex_unlock(&dev->mutex);
d9740a03
IA
173}
174
db210da2
IA
175static bool comedi_clear_board_dev(struct comedi_device *dev)
176{
177 unsigned int i = dev->minor;
178 bool cleared = false;
179
180 mutex_lock(&comedi_board_minor_table_lock);
181 if (dev == comedi_board_minor_table[i]) {
182 comedi_board_minor_table[i] = NULL;
183 cleared = true;
184 }
185 mutex_unlock(&comedi_board_minor_table_lock);
186 return cleared;
187}
188
cb6b79de 189static struct comedi_device *comedi_clear_board_minor(unsigned minor)
d9740a03 190{
cb6b79de 191 struct comedi_device *dev;
d9740a03 192
5b7dba1b 193 mutex_lock(&comedi_board_minor_table_lock);
cb6b79de 194 dev = comedi_board_minor_table[minor];
5b7dba1b
IA
195 comedi_board_minor_table[minor] = NULL;
196 mutex_unlock(&comedi_board_minor_table_lock);
cb6b79de 197 return dev;
d9740a03
IA
198}
199
cb6b79de 200static void comedi_free_board_dev(struct comedi_device *dev)
d9740a03 201{
cb6b79de 202 if (dev) {
52ef9e7c 203 comedi_device_cleanup(dev);
cb6b79de
IA
204 if (dev->class_dev) {
205 device_destroy(comedi_class,
206 MKDEV(COMEDI_MAJOR, dev->minor));
d9740a03 207 }
5b13ed94 208 comedi_dev_put(dev);
d9740a03
IA
209 }
210}
8ab4ed6e 211
bd5b4173 212static struct comedi_subdevice
63ab0395 213*comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned minor)
5b7dba1b 214{
bd5b4173 215 struct comedi_subdevice *s;
5b7dba1b
IA
216 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
217
5b7dba1b 218 mutex_lock(&comedi_subdevice_minor_table_lock);
bd5b4173 219 s = comedi_subdevice_minor_table[i];
63ab0395
IA
220 if (s && s->device != dev)
221 s = NULL;
5b7dba1b 222 mutex_unlock(&comedi_subdevice_minor_table_lock);
bd5b4173 223 return s;
5b7dba1b
IA
224}
225
b449c1ca
IA
226static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor)
227{
228 struct comedi_device *dev;
229
230 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
231 mutex_lock(&comedi_board_minor_table_lock);
232 dev = comedi_dev_get(comedi_board_minor_table[minor]);
233 mutex_unlock(&comedi_board_minor_table_lock);
234 return dev;
235}
236
237static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
238{
239 struct comedi_device *dev;
240 struct comedi_subdevice *s;
241 unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
242
b449c1ca
IA
243 mutex_lock(&comedi_subdevice_minor_table_lock);
244 s = comedi_subdevice_minor_table[i];
245 dev = comedi_dev_get(s ? s->device : NULL);
246 mutex_unlock(&comedi_subdevice_minor_table_lock);
247 return dev;
248}
249
dd630cde
IA
250/**
251 * comedi_dev_get_from_minor - get comedi device by minor device number
252 * @minor: minor device number
253 *
254 * Finds the comedi device associated by the minor device number, if any,
255 * and increments its reference count. The comedi device is prevented from
256 * being freed until a matching call is made to comedi_dev_put().
257 *
258 * Return a pointer to the comedi device if it exists, with its usage
259 * reference incremented. Return NULL if no comedi device exists with the
260 * specified minor device number.
261 */
b449c1ca
IA
262struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
263{
264 if (minor < COMEDI_NUM_BOARD_MINORS)
265 return comedi_dev_get_from_board_minor(minor);
cb3aadae
KH
266
267 return comedi_dev_get_from_subdevice_minor(minor);
b449c1ca
IA
268}
269EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor);
270
43bd33f2 271static struct comedi_subdevice *
da56fdc6 272comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
43bd33f2 273{
bd5b4173 274 struct comedi_subdevice *s;
da56fdc6
IA
275
276 if (minor >= COMEDI_NUM_BOARD_MINORS) {
63ab0395 277 s = comedi_subdevice_from_minor(dev, minor);
88cc30cf 278 if (!s || (s->subdev_flags & SDF_CMD_READ))
bd5b4173 279 return s;
da56fdc6
IA
280 }
281 return dev->read_subdev;
43bd33f2
HS
282}
283
284static struct comedi_subdevice *
da56fdc6 285comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
43bd33f2 286{
bd5b4173 287 struct comedi_subdevice *s;
da56fdc6
IA
288
289 if (minor >= COMEDI_NUM_BOARD_MINORS) {
63ab0395 290 s = comedi_subdevice_from_minor(dev, minor);
88cc30cf 291 if (!s || (s->subdev_flags & SDF_CMD_WRITE))
bd5b4173 292 return s;
da56fdc6
IA
293 }
294 return dev->write_subdev;
43bd33f2
HS
295}
296
20f083c0
IA
297static void comedi_file_reset(struct file *file)
298{
299 struct comedi_file *cfp = file->private_data;
300 struct comedi_device *dev = cfp->dev;
301 struct comedi_subdevice *s, *read_s, *write_s;
302 unsigned int minor = iminor(file_inode(file));
303
304 read_s = dev->read_subdev;
305 write_s = dev->write_subdev;
306 if (minor >= COMEDI_NUM_BOARD_MINORS) {
307 s = comedi_subdevice_from_minor(dev, minor);
88cc30cf 308 if (!s || s->subdev_flags & SDF_CMD_READ)
20f083c0 309 read_s = s;
88cc30cf 310 if (!s || s->subdev_flags & SDF_CMD_WRITE)
20f083c0
IA
311 write_s = s;
312 }
313 cfp->last_attached = dev->attached;
314 cfp->last_detach_count = dev->detach_count;
315 ACCESS_ONCE(cfp->read_subdev) = read_s;
316 ACCESS_ONCE(cfp->write_subdev) = write_s;
317}
318
319static void comedi_file_check(struct file *file)
320{
321 struct comedi_file *cfp = file->private_data;
322 struct comedi_device *dev = cfp->dev;
323
324 if (cfp->last_attached != dev->attached ||
325 cfp->last_detach_count != dev->detach_count)
326 comedi_file_reset(file);
327}
328
329static struct comedi_subdevice *comedi_file_read_subdevice(struct file *file)
330{
331 struct comedi_file *cfp = file->private_data;
332
333 comedi_file_check(file);
334 return ACCESS_ONCE(cfp->read_subdev);
335}
336
337static struct comedi_subdevice *comedi_file_write_subdevice(struct file *file)
338{
339 struct comedi_file *cfp = file->private_data;
340
341 comedi_file_check(file);
342 return ACCESS_ONCE(cfp->write_subdev);
343}
344
883db3d9 345static int resize_async_buffer(struct comedi_device *dev,
482f0a21 346 struct comedi_subdevice *s, unsigned new_size)
a5011a26 347{
482f0a21 348 struct comedi_async *async = s->async;
a5011a26
HS
349 int retval;
350
351 if (new_size > async->max_bufsize)
352 return -EPERM;
353
354 if (s->busy) {
272850f0
HS
355 dev_dbg(dev->class_dev,
356 "subdevice is busy, cannot resize buffer\n");
a5011a26
HS
357 return -EBUSY;
358 }
d4526ab4 359 if (comedi_buf_is_mmapped(s)) {
272850f0
HS
360 dev_dbg(dev->class_dev,
361 "subdevice is mmapped, cannot resize buffer\n");
a5011a26
HS
362 return -EBUSY;
363 }
364
a2aab8b4 365 /* make sure buffer is an integral number of pages (we round up) */
a5011a26
HS
366 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
367
368 retval = comedi_buf_alloc(dev, s, new_size);
369 if (retval < 0)
370 return retval;
371
372 if (s->buf_change) {
d546b896 373 retval = s->buf_change(dev, s);
a5011a26
HS
374 if (retval < 0)
375 return retval;
376 }
377
272850f0
HS
378 dev_dbg(dev->class_dev, "subd %d buffer resized to %i bytes\n",
379 s->index, async->prealloc_bufsz);
a5011a26
HS
380 return 0;
381}
382
383/* sysfs attribute files */
384
e56341ad 385static ssize_t max_read_buffer_kb_show(struct device *csdev,
a5011a26
HS
386 struct device_attribute *attr, char *buf)
387{
c88db469 388 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
389 struct comedi_device *dev;
390 struct comedi_subdevice *s;
72fd9fac 391 unsigned int size = 0;
a5011a26 392
be535c9a 393 dev = comedi_dev_get_from_minor(minor);
5e04c254 394 if (!dev)
c88db469
IA
395 return -ENODEV;
396
7f4656c5 397 mutex_lock(&dev->mutex);
da56fdc6 398 s = comedi_read_subdevice(dev, minor);
72fd9fac
HS
399 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
400 size = s->async->max_bufsize / 1024;
7f4656c5 401 mutex_unlock(&dev->mutex);
a5011a26 402
be535c9a 403 comedi_dev_put(dev);
ecd56ff9 404 return snprintf(buf, PAGE_SIZE, "%u\n", size);
a5011a26
HS
405}
406
e56341ad 407static ssize_t max_read_buffer_kb_store(struct device *csdev,
a5011a26
HS
408 struct device_attribute *attr,
409 const char *buf, size_t count)
410{
c88db469 411 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
412 struct comedi_device *dev;
413 struct comedi_subdevice *s;
72fd9fac
HS
414 unsigned int size;
415 int err;
416
417 err = kstrtouint(buf, 10, &size);
418 if (err)
419 return err;
420 if (size > (UINT_MAX / 1024))
a5011a26 421 return -EINVAL;
72fd9fac 422 size *= 1024;
a5011a26 423
be535c9a 424 dev = comedi_dev_get_from_minor(minor);
5e04c254 425 if (!dev)
c88db469
IA
426 return -ENODEV;
427
7f4656c5 428 mutex_lock(&dev->mutex);
da56fdc6 429 s = comedi_read_subdevice(dev, minor);
72fd9fac
HS
430 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
431 s->async->max_bufsize = size;
432 else
433 err = -EINVAL;
7f4656c5 434 mutex_unlock(&dev->mutex);
a5011a26 435
be535c9a 436 comedi_dev_put(dev);
72fd9fac 437 return err ? err : count;
a5011a26 438}
e56341ad 439static DEVICE_ATTR_RW(max_read_buffer_kb);
a5011a26 440
e56341ad 441static ssize_t read_buffer_kb_show(struct device *csdev,
a5011a26
HS
442 struct device_attribute *attr, char *buf)
443{
c88db469 444 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
445 struct comedi_device *dev;
446 struct comedi_subdevice *s;
72fd9fac 447 unsigned int size = 0;
a5011a26 448
be535c9a 449 dev = comedi_dev_get_from_minor(minor);
5e04c254 450 if (!dev)
c88db469
IA
451 return -ENODEV;
452
7f4656c5 453 mutex_lock(&dev->mutex);
da56fdc6 454 s = comedi_read_subdevice(dev, minor);
72fd9fac
HS
455 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
456 size = s->async->prealloc_bufsz / 1024;
7f4656c5 457 mutex_unlock(&dev->mutex);
a5011a26 458
be535c9a 459 comedi_dev_put(dev);
ecd56ff9 460 return snprintf(buf, PAGE_SIZE, "%u\n", size);
a5011a26
HS
461}
462
e56341ad 463static ssize_t read_buffer_kb_store(struct device *csdev,
a5011a26
HS
464 struct device_attribute *attr,
465 const char *buf, size_t count)
466{
c88db469 467 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
468 struct comedi_device *dev;
469 struct comedi_subdevice *s;
72fd9fac
HS
470 unsigned int size;
471 int err;
472
473 err = kstrtouint(buf, 10, &size);
474 if (err)
475 return err;
476 if (size > (UINT_MAX / 1024))
a5011a26 477 return -EINVAL;
72fd9fac 478 size *= 1024;
a5011a26 479
be535c9a 480 dev = comedi_dev_get_from_minor(minor);
5e04c254 481 if (!dev)
c88db469
IA
482 return -ENODEV;
483
7f4656c5 484 mutex_lock(&dev->mutex);
da56fdc6 485 s = comedi_read_subdevice(dev, minor);
72fd9fac 486 if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
482f0a21 487 err = resize_async_buffer(dev, s, size);
72fd9fac
HS
488 else
489 err = -EINVAL;
7f4656c5 490 mutex_unlock(&dev->mutex);
a5011a26 491
be535c9a 492 comedi_dev_put(dev);
72fd9fac 493 return err ? err : count;
a5011a26 494}
e56341ad 495static DEVICE_ATTR_RW(read_buffer_kb);
883db3d9 496
e56341ad 497static ssize_t max_write_buffer_kb_show(struct device *csdev,
a5011a26
HS
498 struct device_attribute *attr,
499 char *buf)
500{
c88db469 501 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
502 struct comedi_device *dev;
503 struct comedi_subdevice *s;
72fd9fac 504 unsigned int size = 0;
a5011a26 505
be535c9a 506 dev = comedi_dev_get_from_minor(minor);
5e04c254 507 if (!dev)
c88db469
IA
508 return -ENODEV;
509
7f4656c5 510 mutex_lock(&dev->mutex);
da56fdc6 511 s = comedi_write_subdevice(dev, minor);
72fd9fac
HS
512 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
513 size = s->async->max_bufsize / 1024;
7f4656c5 514 mutex_unlock(&dev->mutex);
a5011a26 515
be535c9a 516 comedi_dev_put(dev);
ecd56ff9 517 return snprintf(buf, PAGE_SIZE, "%u\n", size);
a5011a26
HS
518}
519
e56341ad 520static ssize_t max_write_buffer_kb_store(struct device *csdev,
a5011a26
HS
521 struct device_attribute *attr,
522 const char *buf, size_t count)
523{
c88db469 524 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
525 struct comedi_device *dev;
526 struct comedi_subdevice *s;
72fd9fac
HS
527 unsigned int size;
528 int err;
529
530 err = kstrtouint(buf, 10, &size);
531 if (err)
532 return err;
533 if (size > (UINT_MAX / 1024))
a5011a26 534 return -EINVAL;
72fd9fac 535 size *= 1024;
a5011a26 536
be535c9a 537 dev = comedi_dev_get_from_minor(minor);
5e04c254 538 if (!dev)
c88db469
IA
539 return -ENODEV;
540
7f4656c5 541 mutex_lock(&dev->mutex);
da56fdc6 542 s = comedi_write_subdevice(dev, minor);
72fd9fac
HS
543 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
544 s->async->max_bufsize = size;
545 else
546 err = -EINVAL;
7f4656c5 547 mutex_unlock(&dev->mutex);
a5011a26 548
be535c9a 549 comedi_dev_put(dev);
72fd9fac 550 return err ? err : count;
a5011a26 551}
e56341ad 552static DEVICE_ATTR_RW(max_write_buffer_kb);
a5011a26 553
e56341ad 554static ssize_t write_buffer_kb_show(struct device *csdev,
a5011a26
HS
555 struct device_attribute *attr, char *buf)
556{
c88db469 557 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
558 struct comedi_device *dev;
559 struct comedi_subdevice *s;
72fd9fac 560 unsigned int size = 0;
a5011a26 561
be535c9a 562 dev = comedi_dev_get_from_minor(minor);
5e04c254 563 if (!dev)
c88db469
IA
564 return -ENODEV;
565
7f4656c5 566 mutex_lock(&dev->mutex);
da56fdc6 567 s = comedi_write_subdevice(dev, minor);
72fd9fac
HS
568 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
569 size = s->async->prealloc_bufsz / 1024;
7f4656c5 570 mutex_unlock(&dev->mutex);
a5011a26 571
be535c9a 572 comedi_dev_put(dev);
ecd56ff9 573 return snprintf(buf, PAGE_SIZE, "%u\n", size);
a5011a26
HS
574}
575
e56341ad 576static ssize_t write_buffer_kb_store(struct device *csdev,
a5011a26
HS
577 struct device_attribute *attr,
578 const char *buf, size_t count)
579{
c88db469 580 unsigned int minor = MINOR(csdev->devt);
7f4656c5
IA
581 struct comedi_device *dev;
582 struct comedi_subdevice *s;
72fd9fac
HS
583 unsigned int size;
584 int err;
585
586 err = kstrtouint(buf, 10, &size);
587 if (err)
588 return err;
589 if (size > (UINT_MAX / 1024))
a5011a26 590 return -EINVAL;
72fd9fac 591 size *= 1024;
a5011a26 592
be535c9a 593 dev = comedi_dev_get_from_minor(minor);
5e04c254 594 if (!dev)
c88db469
IA
595 return -ENODEV;
596
7f4656c5 597 mutex_lock(&dev->mutex);
da56fdc6 598 s = comedi_write_subdevice(dev, minor);
72fd9fac 599 if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
482f0a21 600 err = resize_async_buffer(dev, s, size);
72fd9fac
HS
601 else
602 err = -EINVAL;
7f4656c5 603 mutex_unlock(&dev->mutex);
a5011a26 604
be535c9a 605 comedi_dev_put(dev);
72fd9fac 606 return err ? err : count;
a5011a26 607}
e56341ad
GKH
608static DEVICE_ATTR_RW(write_buffer_kb);
609
610static struct attribute *comedi_dev_attrs[] = {
611 &dev_attr_max_read_buffer_kb.attr,
612 &dev_attr_read_buffer_kb.attr,
613 &dev_attr_max_write_buffer_kb.attr,
614 &dev_attr_write_buffer_kb.attr,
615 NULL,
a5011a26 616};
e56341ad 617ATTRIBUTE_GROUPS(comedi_dev);
ed9eccbe 618
ef4b4b27
IA
619static void __comedi_clear_subdevice_runflags(struct comedi_subdevice *s,
620 unsigned bits)
621{
622 s->runflags &= ~bits;
623}
624
625static void __comedi_set_subdevice_runflags(struct comedi_subdevice *s,
626 unsigned bits)
627{
628 s->runflags |= bits;
629}
630
cc64ea42
IA
631static void comedi_update_subdevice_runflags(struct comedi_subdevice *s,
632 unsigned mask, unsigned bits)
2aae0076
HS
633{
634 unsigned long flags;
635
636 spin_lock_irqsave(&s->spin_lock, flags);
ef4b4b27
IA
637 __comedi_clear_subdevice_runflags(s, mask);
638 __comedi_set_subdevice_runflags(s, bits & mask);
2aae0076
HS
639 spin_unlock_irqrestore(&s->spin_lock, flags);
640}
641
ef4b4b27
IA
642static unsigned __comedi_get_subdevice_runflags(struct comedi_subdevice *s)
643{
644 return s->runflags;
645}
646
ade1764f 647static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
74120719
HS
648{
649 unsigned long flags;
650 unsigned runflags;
651
652 spin_lock_irqsave(&s->spin_lock, flags);
ef4b4b27 653 runflags = __comedi_get_subdevice_runflags(s);
74120719
HS
654 spin_unlock_irqrestore(&s->spin_lock, flags);
655 return runflags;
656}
74120719 657
b183a836
IA
658static bool comedi_is_runflags_running(unsigned runflags)
659{
660 return runflags & COMEDI_SRF_RUNNING;
661}
662
663static bool comedi_is_runflags_in_error(unsigned runflags)
664{
665 return runflags & COMEDI_SRF_ERROR;
666}
667
dd630cde
IA
668/**
669 * comedi_is_subdevice_running - check if async command running on subdevice
670 * @s: comedi_subdevice struct
671 *
672 * Return true if an asynchronous comedi command is active on the comedi
673 * subdevice, else return false.
674 */
e0dac318
HS
675bool comedi_is_subdevice_running(struct comedi_subdevice *s)
676{
677 unsigned runflags = comedi_get_subdevice_runflags(s);
678
b183a836 679 return comedi_is_runflags_running(runflags);
e0dac318
HS
680}
681EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
682
ef4b4b27
IA
683static bool __comedi_is_subdevice_running(struct comedi_subdevice *s)
684{
685 unsigned runflags = __comedi_get_subdevice_runflags(s);
686
687 return comedi_is_runflags_running(runflags);
688}
689
9682e28c
HS
690static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
691{
692 unsigned runflags = comedi_get_subdevice_runflags(s);
693
38ee1fd3 694 return !(runflags & COMEDI_SRF_BUSY_MASK);
9682e28c
HS
695}
696
8fc369ae
IA
697bool comedi_can_auto_free_spriv(struct comedi_subdevice *s)
698{
699 unsigned runflags = __comedi_get_subdevice_runflags(s);
700
701 return runflags & COMEDI_SRF_FREE_SPRIV;
702}
703
704/**
705 * comedi_set_spriv_auto_free - mark subdevice private data as freeable
706 * @s: comedi_subdevice struct
707 *
708 * Mark the subdevice as having a pointer to private data that can be
709 * automatically freed by the comedi core during the detach.
710 */
711void comedi_set_spriv_auto_free(struct comedi_subdevice *s)
712{
713 __comedi_set_subdevice_runflags(s, COMEDI_SRF_FREE_SPRIV);
714}
715EXPORT_SYMBOL_GPL(comedi_set_spriv_auto_free);
716
588ba6dc 717/**
8fc369ae 718 * comedi_alloc_spriv - Allocate memory for the subdevice private data.
588ba6dc 719 * @s: comedi_subdevice struct
0480bcb9 720 * @size: size of the memory to allocate
588ba6dc
HS
721 *
722 * This also sets the subdevice runflags to allow the core to automatically
723 * free the private data during the detach.
724 */
0480bcb9 725void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
588ba6dc 726{
0480bcb9
HS
727 s->private = kzalloc(size, GFP_KERNEL);
728 if (s->private)
8fc369ae 729 comedi_set_spriv_auto_free(s);
0480bcb9 730 return s->private;
588ba6dc 731}
0480bcb9 732EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
588ba6dc 733
2aae0076 734/*
a2aab8b4 735 * This function restores a subdevice to an idle state.
2aae0076
HS
736 */
737static void do_become_nonbusy(struct comedi_device *dev,
738 struct comedi_subdevice *s)
739{
740 struct comedi_async *async = s->async;
741
cc64ea42 742 comedi_update_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
2aae0076 743 if (async) {
fcc18a9a 744 comedi_buf_reset(s);
2aae0076
HS
745 async->inttrig = NULL;
746 kfree(async->cmd.chanlist);
747 async->cmd.chanlist = NULL;
8da8c86f 748 s->busy = NULL;
258c1dd7 749 wake_up_interruptible_all(&async->wait_head);
2aae0076
HS
750 } else {
751 dev_err(dev->class_dev,
752 "BUG: (?) do_become_nonbusy called with async=NULL\n");
8da8c86f 753 s->busy = NULL;
2aae0076 754 }
2aae0076
HS
755}
756
757static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
758{
759 int ret = 0;
760
f0124630 761 if (comedi_is_subdevice_running(s) && s->cancel)
2aae0076
HS
762 ret = s->cancel(dev, s);
763
764 do_become_nonbusy(dev, s);
765
766 return ret;
767}
768
d19db51a
IA
769void comedi_device_cancel_all(struct comedi_device *dev)
770{
771 struct comedi_subdevice *s;
772 int i;
773
774 if (!dev->attached)
775 return;
776
777 for (i = 0; i < dev->n_subdevices; i++) {
778 s = &dev->subdevices[i];
779 if (s->async)
780 do_cancel(dev, s);
781 }
782}
783
2aae0076
HS
784static int is_device_busy(struct comedi_device *dev)
785{
786 struct comedi_subdevice *s;
787 int i;
788
789 if (!dev->attached)
790 return 0;
791
792 for (i = 0; i < dev->n_subdevices; i++) {
793 s = &dev->subdevices[i];
794 if (s->busy)
795 return 1;
d4526ab4 796 if (s->async && comedi_buf_is_mmapped(s))
2aae0076
HS
797 return 1;
798 }
799
800 return 0;
801}
802
ed9eccbe 803/*
18e01b24
IA
804 * COMEDI_DEVCONFIG ioctl
805 * attaches (and configures) or detaches a legacy device
806 *
807 * arg:
808 * pointer to comedi_devconfig structure (NULL if detaching)
809 *
810 * reads:
811 * comedi_devconfig structure (if attaching)
812 *
813 * writes:
814 * nothing
815 */
0a85b6f0 816static int do_devconfig_ioctl(struct comedi_device *dev,
92d0127c 817 struct comedi_devconfig __user *arg)
ed9eccbe 818{
0707bb04 819 struct comedi_devconfig it;
ed9eccbe
DS
820
821 if (!capable(CAP_SYS_ADMIN))
822 return -EPERM;
823
88cc30cf 824 if (!arg) {
ed9eccbe
DS
825 if (is_device_busy(dev))
826 return -EBUSY;
476b8477 827 if (dev->attached) {
ed9eccbe 828 struct module *driver_module = dev->driver->module;
4bac39f6 829
ed9eccbe
DS
830 comedi_device_detach(dev);
831 module_put(driver_module);
832 }
833 return 0;
834 }
835
bc252fd1 836 if (copy_from_user(&it, arg, sizeof(it)))
ed9eccbe
DS
837 return -EFAULT;
838
839 it.board_name[COMEDI_NAMELEN - 1] = 0;
840
d1843132
HS
841 if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
842 dev_warn(dev->class_dev,
843 "comedi_config --init_data is deprecated\n");
844 return -EINVAL;
ed9eccbe
DS
845 }
846
8ab4ed6e
IA
847 if (dev->minor >= comedi_num_legacy_minors)
848 /* don't re-use dynamically allocated comedi devices */
849 return -EBUSY;
850
b2a644b4
IA
851 /* This increments the driver module count on success. */
852 return comedi_device_attach(dev, &it);
ed9eccbe
DS
853}
854
855/*
18e01b24
IA
856 * COMEDI_BUFCONFIG ioctl
857 * buffer configuration
858 *
859 * arg:
860 * pointer to comedi_bufconfig structure
861 *
862 * reads:
863 * comedi_bufconfig structure
864 *
865 * writes:
866 * modified comedi_bufconfig structure
867 */
92d0127c
GKH
868static int do_bufconfig_ioctl(struct comedi_device *dev,
869 struct comedi_bufconfig __user *arg)
ed9eccbe 870{
be6aba4a 871 struct comedi_bufconfig bc;
d163679c 872 struct comedi_async *async;
34c43922 873 struct comedi_subdevice *s;
883db3d9 874 int retval = 0;
ed9eccbe 875
bc252fd1 876 if (copy_from_user(&bc, arg, sizeof(bc)))
ed9eccbe
DS
877 return -EFAULT;
878
11f80ddf 879 if (bc.subdevice >= dev->n_subdevices)
ed9eccbe
DS
880 return -EINVAL;
881
b077f2cd 882 s = &dev->subdevices[bc.subdevice];
ed9eccbe
DS
883 async = s->async;
884
885 if (!async) {
272850f0
HS
886 dev_dbg(dev->class_dev,
887 "subdevice does not have async capability\n");
ed9eccbe
DS
888 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) {
482f0a21 901 retval = resize_async_buffer(dev, s, bc.size);
883db3d9
FMH
902 if (retval < 0)
903 return retval;
ed9eccbe
DS
904 }
905
906 bc.size = async->prealloc_bufsz;
907 bc.maximum_size = async->max_bufsize;
908
476b8477 909copyback:
bc252fd1 910 if (copy_to_user(arg, &bc, sizeof(bc)))
ed9eccbe
DS
911 return -EFAULT;
912
913 return 0;
914}
915
916/*
18e01b24
IA
917 * 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 */
0a85b6f0 929static int do_devinfo_ioctl(struct comedi_device *dev,
92d0127c
GKH
930 struct comedi_devinfo __user *arg,
931 struct file *file)
ed9eccbe 932{
0e700923
HS
933 struct comedi_subdevice *s;
934 struct comedi_devinfo devinfo;
ed9eccbe
DS
935
936 memset(&devinfo, 0, sizeof(devinfo));
937
938 /* fill devinfo structure */
939 devinfo.version_code = COMEDI_VERSION_CODE;
940 devinfo.n_subdevs = dev->n_subdevices;
819cbb12
VK
941 strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
942 strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
ed9eccbe 943
20f083c0 944 s = comedi_file_read_subdevice(file);
0e700923 945 if (s)
90a35c15 946 devinfo.read_subdevice = s->index;
476b8477 947 else
ed9eccbe 948 devinfo.read_subdevice = -1;
476b8477 949
20f083c0 950 s = comedi_file_write_subdevice(file);
0e700923 951 if (s)
90a35c15 952 devinfo.write_subdevice = s->index;
476b8477 953 else
ed9eccbe 954 devinfo.write_subdevice = -1;
ed9eccbe 955
bc252fd1 956 if (copy_to_user(arg, &devinfo, sizeof(devinfo)))
ed9eccbe
DS
957 return -EFAULT;
958
959 return 0;
960}
961
962/*
18e01b24
IA
963 * COMEDI_SUBDINFO ioctl
964 * subdevices info
965 *
966 * arg:
967 * pointer to array of comedi_subdinfo structures
968 *
969 * reads:
970 * nothing
971 *
972 * writes:
973 * array of comedi_subdinfo structures
974 */
0a85b6f0 975static int do_subdinfo_ioctl(struct comedi_device *dev,
92d0127c 976 struct comedi_subdinfo __user *arg, void *file)
ed9eccbe
DS
977{
978 int ret, i;
bd52efbb 979 struct comedi_subdinfo *tmp, *us;
34c43922 980 struct comedi_subdevice *s;
ed9eccbe 981
bc252fd1 982 tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL);
ed9eccbe
DS
983 if (!tmp)
984 return -ENOMEM;
985
986 /* fill subdinfo structs */
987 for (i = 0; i < dev->n_subdevices; i++) {
b077f2cd 988 s = &dev->subdevices[i];
ed9eccbe
DS
989 us = tmp + i;
990
991 us->type = s->type;
992 us->n_chan = s->n_chan;
993 us->subd_flags = s->subdev_flags;
f0124630 994 if (comedi_is_subdevice_running(s))
ed9eccbe
DS
995 us->subd_flags |= SDF_RUNNING;
996#define TIMER_nanosec 5 /* backwards compatibility */
997 us->timer_type = TIMER_nanosec;
998 us->len_chanlist = s->len_chanlist;
999 us->maxdata = s->maxdata;
1000 if (s->range_table) {
1001 us->range_type =
476b8477 1002 (i << 24) | (0 << 16) | (s->range_table->length);
ed9eccbe
DS
1003 } else {
1004 us->range_type = 0; /* XXX */
1005 }
ed9eccbe
DS
1006
1007 if (s->busy)
1008 us->subd_flags |= SDF_BUSY;
1009 if (s->busy == file)
1010 us->subd_flags |= SDF_BUSY_OWNER;
1011 if (s->lock)
1012 us->subd_flags |= SDF_LOCKED;
1013 if (s->lock == file)
1014 us->subd_flags |= SDF_LOCK_OWNER;
1015 if (!s->maxdata && s->maxdata_list)
1016 us->subd_flags |= SDF_MAXDATA;
ed9eccbe
DS
1017 if (s->range_table_list)
1018 us->subd_flags |= SDF_RANGETYPE;
1019 if (s->do_cmd)
1020 us->subd_flags |= SDF_CMD;
1021
1022 if (s->insn_bits != &insn_inval)
1023 us->insn_bits_support = COMEDI_SUPPORTED;
1024 else
1025 us->insn_bits_support = COMEDI_UNSUPPORTED;
ed9eccbe
DS
1026 }
1027
bc252fd1 1028 ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp));
ed9eccbe
DS
1029
1030 kfree(tmp);
1031
1032 return ret ? -EFAULT : 0;
1033}
1034
1035/*
18e01b24
IA
1036 * COMEDI_CHANINFO ioctl
1037 * subdevice channel info
1038 *
1039 * arg:
1040 * pointer to comedi_chaninfo structure
1041 *
1042 * reads:
1043 * comedi_chaninfo structure
1044 *
1045 * writes:
1046 * array of maxdata values to chaninfo->maxdata_list if requested
1047 * array of range table lengths to chaninfo->range_table_list if requested
1048 */
0a85b6f0 1049static int do_chaninfo_ioctl(struct comedi_device *dev,
92d0127c 1050 struct comedi_chaninfo __user *arg)
ed9eccbe 1051{
34c43922 1052 struct comedi_subdevice *s;
a18b416d 1053 struct comedi_chaninfo it;
ed9eccbe 1054
bc252fd1 1055 if (copy_from_user(&it, arg, sizeof(it)))
ed9eccbe
DS
1056 return -EFAULT;
1057
1058 if (it.subdev >= dev->n_subdevices)
1059 return -EINVAL;
b077f2cd 1060 s = &dev->subdevices[it.subdev];
ed9eccbe
DS
1061
1062 if (it.maxdata_list) {
1063 if (s->maxdata || !s->maxdata_list)
1064 return -EINVAL;
1065 if (copy_to_user(it.maxdata_list, s->maxdata_list,
790c5541 1066 s->n_chan * sizeof(unsigned int)))
ed9eccbe
DS
1067 return -EFAULT;
1068 }
1069
64d9b1d2
IA
1070 if (it.flaglist)
1071 return -EINVAL; /* flaglist not supported */
ed9eccbe
DS
1072
1073 if (it.rangelist) {
1074 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
1081 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
476b8477 1082 (s->range_table_list[i]->length);
81604d43
VK
1083 if (put_user(x, it.rangelist + i))
1084 return -EFAULT;
ed9eccbe 1085 }
ed9eccbe
DS
1086 }
1087
1088 return 0;
1089}
1090
18e01b24
IA
1091/*
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 */
92d0127c 1104static int do_bufinfo_ioctl(struct comedi_device *dev,
53fa827e 1105 struct comedi_bufinfo __user *arg, void *file)
ed9eccbe 1106{
9aa5339a 1107 struct comedi_bufinfo bi;
34c43922 1108 struct comedi_subdevice *s;
d163679c 1109 struct comedi_async *async;
ed9eccbe 1110
bc252fd1 1111 if (copy_from_user(&bi, arg, sizeof(bi)))
ed9eccbe
DS
1112 return -EFAULT;
1113
7b1a5e2f 1114 if (bi.subdevice >= dev->n_subdevices)
ed9eccbe
DS
1115 return -EINVAL;
1116
b077f2cd 1117 s = &dev->subdevices[bi.subdevice];
53fa827e 1118
ed9eccbe
DS
1119 async = s->async;
1120
1121 if (!async) {
272850f0
HS
1122 dev_dbg(dev->class_dev,
1123 "subdevice does not have async capability\n");
ed9eccbe
DS
1124 bi.buf_write_ptr = 0;
1125 bi.buf_read_ptr = 0;
1126 bi.buf_write_count = 0;
1127 bi.buf_read_count = 0;
4772c018
IA
1128 bi.bytes_read = 0;
1129 bi.bytes_written = 0;
ed9eccbe
DS
1130 goto copyback;
1131 }
53fa827e
IA
1132 if (!s->busy) {
1133 bi.bytes_read = 0;
1134 bi.bytes_written = 0;
1135 goto copyback_position;
1136 }
1137 if (s->busy != file)
1138 return -EACCES;
ed9eccbe 1139
75f6108f 1140 if (bi.bytes_read && !(async->cmd.flags & CMDF_WRITE)) {
d13be55a 1141 bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read);
f1df8662 1142 comedi_buf_read_free(s, bi.bytes_read);
ed9eccbe 1143
9682e28c 1144 if (comedi_is_subdevice_idle(s) &&
f4f3f7cf 1145 comedi_buf_n_bytes_ready(s) == 0) {
ed9eccbe
DS
1146 do_become_nonbusy(dev, s);
1147 }
1148 }
1149
75f6108f 1150 if (bi.bytes_written && (async->cmd.flags & CMDF_WRITE)) {
ed9eccbe 1151 bi.bytes_written =
24e894bb 1152 comedi_buf_write_alloc(s, bi.bytes_written);
940dd35d 1153 comedi_buf_write_free(s, bi.bytes_written);
ed9eccbe
DS
1154 }
1155
53fa827e 1156copyback_position:
ed9eccbe
DS
1157 bi.buf_write_count = async->buf_write_count;
1158 bi.buf_write_ptr = async->buf_write_ptr;
1159 bi.buf_read_count = async->buf_read_count;
1160 bi.buf_read_ptr = async->buf_read_ptr;
1161
476b8477 1162copyback:
bc252fd1 1163 if (copy_to_user(arg, &bi, sizeof(bi)))
ed9eccbe
DS
1164 return -EFAULT;
1165
1166 return 0;
1167}
1168
0a85b6f0
MT
1169static int check_insn_config_length(struct comedi_insn *insn,
1170 unsigned int *data)
ed9eccbe 1171{
476b8477
GKH
1172 if (insn->n < 1)
1173 return -EINVAL;
ed9eccbe
DS
1174
1175 switch (data[0]) {
1176 case INSN_CONFIG_DIO_OUTPUT:
1177 case INSN_CONFIG_DIO_INPUT:
1178 case INSN_CONFIG_DISARM:
1179 case INSN_CONFIG_RESET:
1180 if (insn->n == 1)
1181 return 0;
1182 break;
1183 case INSN_CONFIG_ARM:
1184 case INSN_CONFIG_DIO_QUERY:
1185 case INSN_CONFIG_BLOCK_SIZE:
1186 case INSN_CONFIG_FILTER:
1187 case INSN_CONFIG_SERIAL_CLOCK:
1188 case INSN_CONFIG_BIDIRECTIONAL_DATA:
1189 case INSN_CONFIG_ALT_SOURCE:
1190 case INSN_CONFIG_SET_COUNTER_MODE:
1191 case INSN_CONFIG_8254_READ_STATUS:
1192 case INSN_CONFIG_SET_ROUTING:
1193 case INSN_CONFIG_GET_ROUTING:
1194 case INSN_CONFIG_GET_PWM_STATUS:
1195 case INSN_CONFIG_PWM_SET_PERIOD:
1196 case INSN_CONFIG_PWM_GET_PERIOD:
1197 if (insn->n == 2)
1198 return 0;
1199 break;
1200 case INSN_CONFIG_SET_GATE_SRC:
1201 case INSN_CONFIG_GET_GATE_SRC:
1202 case INSN_CONFIG_SET_CLOCK_SRC:
1203 case INSN_CONFIG_GET_CLOCK_SRC:
1204 case INSN_CONFIG_SET_OTHER_SRC:
1205 case INSN_CONFIG_GET_COUNTER_STATUS:
1206 case INSN_CONFIG_PWM_SET_H_BRIDGE:
1207 case INSN_CONFIG_PWM_GET_H_BRIDGE:
1208 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
1209 if (insn->n == 3)
1210 return 0;
1211 break;
1212 case INSN_CONFIG_PWM_OUTPUT:
1213 case INSN_CONFIG_ANALOG_TRIG:
1214 if (insn->n == 5)
1215 return 0;
1216 break;
b0a2b6d8
IA
1217 case INSN_CONFIG_DIGITAL_TRIG:
1218 if (insn->n == 6)
1219 return 0;
1220 break;
a2aab8b4
IA
1221 /*
1222 * by default we allow the insn since we don't have checks for
1223 * all possible cases yet
1224 */
ed9eccbe 1225 default:
c2ad078b 1226 pr_warn("No check for data length of config insn id %i is implemented\n",
4f870fe6 1227 data[0]);
c2ad078b
HS
1228 pr_warn("Add a check to %s in %s\n", __func__, __FILE__);
1229 pr_warn("Assuming n=%i is correct\n", insn->n);
ed9eccbe 1230 return 0;
ed9eccbe
DS
1231 }
1232 return -EINVAL;
1233}
1234
0a85b6f0
MT
1235static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
1236 unsigned int *data, void *file)
ed9eccbe 1237{
34c43922 1238 struct comedi_subdevice *s;
ed9eccbe
DS
1239 int ret = 0;
1240 int i;
1241
1242 if (insn->insn & INSN_MASK_SPECIAL) {
1243 /* a non-subdevice instruction */
1244
1245 switch (insn->insn) {
1246 case INSN_GTOD:
1247 {
1248 struct timeval tv;
1249
1250 if (insn->n != 2) {
1251 ret = -EINVAL;
1252 break;
1253 }
1254
1255 do_gettimeofday(&tv);
1256 data[0] = tv.tv_sec;
1257 data[1] = tv.tv_usec;
1258 ret = 2;
1259
1260 break;
1261 }
1262 case INSN_WAIT:
1263 if (insn->n != 1 || data[0] >= 100000) {
1264 ret = -EINVAL;
1265 break;
1266 }
1267 udelay(data[0] / 1000);
1268 ret = 1;
1269 break;
1270 case INSN_INTTRIG:
1271 if (insn->n != 1) {
1272 ret = -EINVAL;
1273 break;
1274 }
1275 if (insn->subdev >= dev->n_subdevices) {
272850f0
HS
1276 dev_dbg(dev->class_dev,
1277 "%d not usable subdevice\n",
ed9eccbe
DS
1278 insn->subdev);
1279 ret = -EINVAL;
1280 break;
1281 }
b077f2cd 1282 s = &dev->subdevices[insn->subdev];
ed9eccbe 1283 if (!s->async) {
272850f0 1284 dev_dbg(dev->class_dev, "no async\n");
ed9eccbe
DS
1285 ret = -EINVAL;
1286 break;
1287 }
1288 if (!s->async->inttrig) {
272850f0 1289 dev_dbg(dev->class_dev, "no inttrig\n");
ed9eccbe
DS
1290 ret = -EAGAIN;
1291 break;
1292 }
5d06e3df 1293 ret = s->async->inttrig(dev, s, data[0]);
ed9eccbe
DS
1294 if (ret >= 0)
1295 ret = 1;
1296 break;
1297 default:
272850f0 1298 dev_dbg(dev->class_dev, "invalid insn\n");
ed9eccbe
DS
1299 ret = -EINVAL;
1300 break;
1301 }
1302 } else {
1303 /* a subdevice instruction */
790c5541 1304 unsigned int maxdata;
ed9eccbe
DS
1305
1306 if (insn->subdev >= dev->n_subdevices) {
272850f0
HS
1307 dev_dbg(dev->class_dev, "subdevice %d out of range\n",
1308 insn->subdev);
ed9eccbe
DS
1309 ret = -EINVAL;
1310 goto out;
1311 }
b077f2cd 1312 s = &dev->subdevices[insn->subdev];
ed9eccbe
DS
1313
1314 if (s->type == COMEDI_SUBD_UNUSED) {
272850f0
HS
1315 dev_dbg(dev->class_dev, "%d not usable subdevice\n",
1316 insn->subdev);
ed9eccbe
DS
1317 ret = -EIO;
1318 goto out;
1319 }
1320
1321 /* are we locked? (ioctl lock) */
1322 if (s->lock && s->lock != file) {
272850f0 1323 dev_dbg(dev->class_dev, "device locked\n");
ed9eccbe
DS
1324 ret = -EACCES;
1325 goto out;
1326 }
1327
0fd0ca75 1328 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
476b8477 1329 if (ret < 0) {
ed9eccbe 1330 ret = -EINVAL;
272850f0 1331 dev_dbg(dev->class_dev, "bad chanspec\n");
ed9eccbe
DS
1332 goto out;
1333 }
1334
1335 if (s->busy) {
1336 ret = -EBUSY;
1337 goto out;
1338 }
1339 /* This looks arbitrary. It is. */
1340 s->busy = &parse_insn;
1341 switch (insn->insn) {
1342 case INSN_READ:
1343 ret = s->insn_read(dev, s, insn, data);
22ca19d9
HS
1344 if (ret == -ETIMEDOUT) {
1345 dev_dbg(dev->class_dev,
1346 "subdevice %d read instruction timed out\n",
1347 s->index);
1348 }
ed9eccbe
DS
1349 break;
1350 case INSN_WRITE:
1351 maxdata = s->maxdata_list
476b8477
GKH
1352 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1353 : s->maxdata;
ed9eccbe
DS
1354 for (i = 0; i < insn->n; ++i) {
1355 if (data[i] > maxdata) {
1356 ret = -EINVAL;
272850f0
HS
1357 dev_dbg(dev->class_dev,
1358 "bad data value(s)\n");
ed9eccbe
DS
1359 break;
1360 }
1361 }
22ca19d9 1362 if (ret == 0) {
ed9eccbe 1363 ret = s->insn_write(dev, s, insn, data);
22ca19d9
HS
1364 if (ret == -ETIMEDOUT) {
1365 dev_dbg(dev->class_dev,
1366 "subdevice %d write instruction timed out\n",
1367 s->index);
1368 }
1369 }
ed9eccbe
DS
1370 break;
1371 case INSN_BITS:
1372 if (insn->n != 2) {
1373 ret = -EINVAL;
2f644ccf 1374 } else {
a2aab8b4
IA
1375 /*
1376 * Most drivers ignore the base channel in
2f644ccf 1377 * insn->chanspec. Fix this here if
a2aab8b4
IA
1378 * the subdevice has <= 32 channels.
1379 */
36efbacd
HS
1380 unsigned int orig_mask = data[0];
1381 unsigned int shift = 0;
2f644ccf 1382
2f644ccf
IA
1383 if (s->n_chan <= 32) {
1384 shift = CR_CHAN(insn->chanspec);
1385 if (shift > 0) {
1386 insn->chanspec = 0;
1387 data[0] <<= shift;
1388 data[1] <<= shift;
1389 }
36efbacd 1390 }
2f644ccf
IA
1391 ret = s->insn_bits(dev, s, insn, data);
1392 data[0] = orig_mask;
1393 if (shift > 0)
1394 data[1] >>= shift;
ed9eccbe 1395 }
ed9eccbe
DS
1396 break;
1397 case INSN_CONFIG:
1398 ret = check_insn_config_length(insn, data);
1399 if (ret)
1400 break;
1401 ret = s->insn_config(dev, s, insn, data);
1402 break;
1403 default:
1404 ret = -EINVAL;
1405 break;
1406 }
1407
1408 s->busy = NULL;
1409 }
1410
476b8477 1411out:
ed9eccbe
DS
1412 return ret;
1413}
1414
5b6cbd87 1415/*
18e01b24
IA
1416 * COMEDI_INSNLIST ioctl
1417 * synchronous instruction list
5b6cbd87 1418 *
18e01b24
IA
1419 * arg:
1420 * pointer to comedi_insnlist structure
5b6cbd87 1421 *
18e01b24
IA
1422 * reads:
1423 * comedi_insnlist structure
1424 * array of comedi_insn structures from insnlist->insns pointer
1425 * data (for writes) from insns[].data pointers
5b6cbd87 1426 *
18e01b24
IA
1427 * writes:
1428 * data (for reads) to insns[].data pointers
5b6cbd87
HS
1429 */
1430/* arbitrary limits */
1431#define MAX_SAMPLES 256
1432static int do_insnlist_ioctl(struct comedi_device *dev,
1433 struct comedi_insnlist __user *arg, void *file)
1434{
1435 struct comedi_insnlist insnlist;
1436 struct comedi_insn *insns = NULL;
1437 unsigned int *data = NULL;
1438 int i = 0;
1439 int ret = 0;
1440
1441 if (copy_from_user(&insnlist, arg, sizeof(insnlist)))
1442 return -EFAULT;
1443
f4a8f528 1444 data = kmalloc_array(MAX_SAMPLES, sizeof(unsigned int), GFP_KERNEL);
5b6cbd87 1445 if (!data) {
5b6cbd87
HS
1446 ret = -ENOMEM;
1447 goto error;
1448 }
1449
1450 insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
1451 if (!insns) {
5b6cbd87
HS
1452 ret = -ENOMEM;
1453 goto error;
1454 }
1455
1456 if (copy_from_user(insns, insnlist.insns,
1457 sizeof(*insns) * insnlist.n_insns)) {
272850f0 1458 dev_dbg(dev->class_dev, "copy_from_user failed\n");
5b6cbd87
HS
1459 ret = -EFAULT;
1460 goto error;
1461 }
1462
1463 for (i = 0; i < insnlist.n_insns; i++) {
1464 if (insns[i].n > MAX_SAMPLES) {
272850f0
HS
1465 dev_dbg(dev->class_dev,
1466 "number of samples too large\n");
5b6cbd87
HS
1467 ret = -EINVAL;
1468 goto error;
1469 }
1470 if (insns[i].insn & INSN_MASK_WRITE) {
1471 if (copy_from_user(data, insns[i].data,
1472 insns[i].n * sizeof(unsigned int))) {
272850f0
HS
1473 dev_dbg(dev->class_dev,
1474 "copy_from_user failed\n");
5b6cbd87
HS
1475 ret = -EFAULT;
1476 goto error;
1477 }
1478 }
1479 ret = parse_insn(dev, insns + i, data, file);
1480 if (ret < 0)
1481 goto error;
1482 if (insns[i].insn & INSN_MASK_READ) {
1483 if (copy_to_user(insns[i].data, data,
1484 insns[i].n * sizeof(unsigned int))) {
272850f0
HS
1485 dev_dbg(dev->class_dev,
1486 "copy_to_user failed\n");
5b6cbd87
HS
1487 ret = -EFAULT;
1488 goto error;
1489 }
1490 }
1491 if (need_resched())
1492 schedule();
1493 }
1494
1495error:
1496 kfree(insns);
1497 kfree(data);
1498
1499 if (ret < 0)
1500 return ret;
1501 return i;
1502}
1503
ed9eccbe 1504/*
18e01b24
IA
1505 * COMEDI_INSN ioctl
1506 * synchronous instruction
ed9eccbe 1507 *
18e01b24
IA
1508 * arg:
1509 * pointer to comedi_insn structure
ed9eccbe 1510 *
18e01b24
IA
1511 * reads:
1512 * comedi_insn structure
1513 * data (for writes) from insn->data pointer
ed9eccbe 1514 *
18e01b24
IA
1515 * writes:
1516 * data (for reads) to insn->data pointer
ed9eccbe 1517 */
92d0127c
GKH
1518static int do_insn_ioctl(struct comedi_device *dev,
1519 struct comedi_insn __user *arg, void *file)
ed9eccbe 1520{
90035c08 1521 struct comedi_insn insn;
790c5541 1522 unsigned int *data = NULL;
ed9eccbe
DS
1523 int ret = 0;
1524
f4a8f528 1525 data = kmalloc_array(MAX_SAMPLES, sizeof(unsigned int), GFP_KERNEL);
ed9eccbe
DS
1526 if (!data) {
1527 ret = -ENOMEM;
1528 goto error;
1529 }
1530
bc252fd1 1531 if (copy_from_user(&insn, arg, sizeof(insn))) {
ed9eccbe
DS
1532 ret = -EFAULT;
1533 goto error;
1534 }
1535
1536 /* This is where the behavior of insn and insnlist deviate. */
1537 if (insn.n > MAX_SAMPLES)
1538 insn.n = MAX_SAMPLES;
1539 if (insn.insn & INSN_MASK_WRITE) {
21fe2eea
M
1540 if (copy_from_user(data,
1541 insn.data,
1542 insn.n * sizeof(unsigned int))) {
ed9eccbe
DS
1543 ret = -EFAULT;
1544 goto error;
1545 }
1546 }
1547 ret = parse_insn(dev, &insn, data, file);
1548 if (ret < 0)
1549 goto error;
1550 if (insn.insn & INSN_MASK_READ) {
21fe2eea
M
1551 if (copy_to_user(insn.data,
1552 data,
1553 insn.n * sizeof(unsigned int))) {
ed9eccbe
DS
1554 ret = -EFAULT;
1555 goto error;
1556 }
1557 }
1558 ret = insn.n;
1559
476b8477
GKH
1560error:
1561 kfree(data);
ed9eccbe
DS
1562
1563 return ret;
1564}
1565
87ece583
HS
1566static int __comedi_get_user_cmd(struct comedi_device *dev,
1567 struct comedi_cmd __user *arg,
1568 struct comedi_cmd *cmd)
ed9eccbe 1569{
34c43922 1570 struct comedi_subdevice *s;
ed9eccbe 1571
87ece583 1572 if (copy_from_user(cmd, arg, sizeof(*cmd))) {
272850f0 1573 dev_dbg(dev->class_dev, "bad cmd address\n");
ed9eccbe
DS
1574 return -EFAULT;
1575 }
ed9eccbe 1576
87ece583
HS
1577 if (cmd->subdev >= dev->n_subdevices) {
1578 dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev);
ed9eccbe
DS
1579 return -ENODEV;
1580 }
1581
87ece583 1582 s = &dev->subdevices[cmd->subdev];
ed9eccbe
DS
1583
1584 if (s->type == COMEDI_SUBD_UNUSED) {
b2f48741
YD
1585 dev_dbg(dev->class_dev, "%d not valid subdevice\n",
1586 cmd->subdev);
ed9eccbe
DS
1587 return -EIO;
1588 }
1589
1590 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
272850f0 1591 dev_dbg(dev->class_dev,
b2f48741
YD
1592 "subdevice %d does not support commands\n",
1593 cmd->subdev);
ed9eccbe
DS
1594 return -EIO;
1595 }
1596
87ece583
HS
1597 /* make sure channel/gain list isn't too long */
1598 if (cmd->chanlist_len > s->len_chanlist) {
1599 dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n",
1600 cmd->chanlist_len, s->len_chanlist);
1601 return -EINVAL;
1602 }
1603
5d070cf2
IA
1604 /*
1605 * Set the CMDF_WRITE flag to the correct state if the subdevice
1606 * supports only "read" commands or only "write" commands.
1607 */
1608 switch (s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) {
1609 case SDF_CMD_READ:
1610 cmd->flags &= ~CMDF_WRITE;
1611 break;
1612 case SDF_CMD_WRITE:
1613 cmd->flags |= CMDF_WRITE;
1614 break;
1615 default:
1616 break;
1617 }
1618
87ece583
HS
1619 return 0;
1620}
1621
c6cd0eef
HS
1622static int __comedi_get_user_chanlist(struct comedi_device *dev,
1623 struct comedi_subdevice *s,
1624 unsigned int __user *user_chanlist,
1625 struct comedi_cmd *cmd)
1626{
1627 unsigned int *chanlist;
1628 int ret;
1629
238b5ad8 1630 cmd->chanlist = NULL;
c6cd0eef
HS
1631 chanlist = memdup_user(user_chanlist,
1632 cmd->chanlist_len * sizeof(unsigned int));
1633 if (IS_ERR(chanlist))
1634 return PTR_ERR(chanlist);
1635
1636 /* make sure each element in channel/gain list is valid */
1637 ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist);
1638 if (ret < 0) {
1639 kfree(chanlist);
1640 return ret;
1641 }
1642
1643 cmd->chanlist = chanlist;
1644
1645 return 0;
1646}
1647
18e01b24
IA
1648/*
1649 * COMEDI_CMD ioctl
1650 * asynchronous acquisition command set-up
1651 *
1652 * arg:
1653 * pointer to comedi_cmd structure
1654 *
1655 * reads:
1656 * comedi_cmd structure
1657 * channel/range list from cmd->chanlist pointer
1658 *
1659 * writes:
1660 * possibly modified comedi_cmd structure (when -EAGAIN returned)
1661 */
87ece583
HS
1662static int do_cmd_ioctl(struct comedi_device *dev,
1663 struct comedi_cmd __user *arg, void *file)
1664{
1665 struct comedi_cmd cmd;
1666 struct comedi_subdevice *s;
1667 struct comedi_async *async;
1668 unsigned int __user *user_chanlist;
1669 int ret;
1670
1671 /* get the user's cmd and do some simple validation */
1672 ret = __comedi_get_user_cmd(dev, arg, &cmd);
1673 if (ret)
1674 return ret;
1675
1676 /* save user's chanlist pointer so it can be restored later */
1677 user_chanlist = (unsigned int __user *)cmd.chanlist;
1678
1679 s = &dev->subdevices[cmd.subdev];
1680 async = s->async;
1681
ed9eccbe
DS
1682 /* are we locked? (ioctl lock) */
1683 if (s->lock && s->lock != file) {
272850f0 1684 dev_dbg(dev->class_dev, "subdevice locked\n");
ed9eccbe
DS
1685 return -EACCES;
1686 }
1687
1688 /* are we busy? */
1689 if (s->busy) {
272850f0 1690 dev_dbg(dev->class_dev, "subdevice busy\n");
ed9eccbe
DS
1691 return -EBUSY;
1692 }
ed9eccbe 1693
ed9eccbe 1694 /* make sure channel/gain list isn't too short */
88bc0574 1695 if (cmd.chanlist_len < 1) {
272850f0 1696 dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n",
88bc0574 1697 cmd.chanlist_len);
4b18f08b 1698 return -EINVAL;
ed9eccbe
DS
1699 }
1700
88bc0574 1701 async->cmd = cmd;
ed9eccbe 1702 async->cmd.data = NULL;
ed9eccbe 1703
c6cd0eef
HS
1704 /* load channel/gain list */
1705 ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd);
1706 if (ret)
ed9eccbe 1707 goto cleanup;
ed9eccbe
DS
1708
1709 ret = s->do_cmdtest(dev, s, &async->cmd);
1710
b0446a21 1711 if (async->cmd.flags & CMDF_BOGUS || ret) {
272850f0 1712 dev_dbg(dev->class_dev, "test returned %d\n", ret);
88bc0574 1713 cmd = async->cmd;
476b8477 1714 /* restore chanlist pointer before copying back */
95bc359f 1715 cmd.chanlist = (unsigned int __force *)user_chanlist;
88bc0574 1716 cmd.data = NULL;
bc252fd1 1717 if (copy_to_user(arg, &cmd, sizeof(cmd))) {
272850f0 1718 dev_dbg(dev->class_dev, "fault writing cmd\n");
ed9eccbe
DS
1719 ret = -EFAULT;
1720 goto cleanup;
1721 }
1722 ret = -EAGAIN;
1723 goto cleanup;
1724 }
1725
1726 if (!async->prealloc_bufsz) {
1727 ret = -ENOMEM;
272850f0 1728 dev_dbg(dev->class_dev, "no buffer (?)\n");
ed9eccbe
DS
1729 goto cleanup;
1730 }
1731
fcc18a9a 1732 comedi_buf_reset(s);
ed9eccbe 1733
781f933c 1734 async->cb_mask = COMEDI_CB_BLOCK | COMEDI_CB_CANCEL_MASK;
d8bff6e3 1735 if (async->cmd.flags & CMDF_WAKE_EOS)
ed9eccbe 1736 async->cb_mask |= COMEDI_CB_EOS;
ed9eccbe 1737
cc64ea42
IA
1738 comedi_update_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
1739 COMEDI_SRF_RUNNING);
ed9eccbe 1740
84bb0bcc
HS
1741 /*
1742 * Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
1743 * race with comedi_read() or comedi_write().
1744 */
4b18f08b 1745 s->busy = file;
ed9eccbe
DS
1746 ret = s->do_cmd(dev, s);
1747 if (ret == 0)
1748 return 0;
1749
476b8477 1750cleanup:
ed9eccbe
DS
1751 do_become_nonbusy(dev, s);
1752
1753 return ret;
1754}
1755
1756/*
18e01b24 1757 * COMEDI_CMDTEST ioctl
69e98df7 1758 * asynchronous acquisition command testing
18e01b24
IA
1759 *
1760 * arg:
1761 * pointer to comedi_cmd structure
1762 *
1763 * reads:
1764 * comedi_cmd structure
1765 * channel/range list from cmd->chanlist pointer
1766 *
1767 * writes:
1768 * possibly modified comedi_cmd structure
1769 */
92d0127c
GKH
1770static int do_cmdtest_ioctl(struct comedi_device *dev,
1771 struct comedi_cmd __user *arg, void *file)
ed9eccbe 1772{
f8348677 1773 struct comedi_cmd cmd;
34c43922 1774 struct comedi_subdevice *s;
95bc359f 1775 unsigned int __user *user_chanlist;
87ece583
HS
1776 int ret;
1777
1778 /* get the user's cmd and do some simple validation */
1779 ret = __comedi_get_user_cmd(dev, arg, &cmd);
1780 if (ret)
1781 return ret;
ed9eccbe 1782
476b8477 1783 /* save user's chanlist pointer so it can be restored later */
95bc359f 1784 user_chanlist = (unsigned int __user *)cmd.chanlist;
ed9eccbe 1785
f8348677 1786 s = &dev->subdevices[cmd.subdev];
ed9eccbe 1787
6cab7a37
IA
1788 /* user_chanlist can be NULL for COMEDI_CMDTEST ioctl */
1789 if (user_chanlist) {
1790 /* load channel/gain list */
1791 ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
1792 if (ret)
1793 return ret;
1794 }
ed9eccbe 1795
f8348677 1796 ret = s->do_cmdtest(dev, s, &cmd);
ed9eccbe 1797
238b5ad8
IA
1798 kfree(cmd.chanlist); /* free kernel copy of user chanlist */
1799
476b8477 1800 /* restore chanlist pointer before copying back */
95bc359f 1801 cmd.chanlist = (unsigned int __force *)user_chanlist;
ed9eccbe 1802
bc252fd1 1803 if (copy_to_user(arg, &cmd, sizeof(cmd))) {
272850f0 1804 dev_dbg(dev->class_dev, "bad cmd address\n");
ed9eccbe 1805 ret = -EFAULT;
ed9eccbe 1806 }
c6cd0eef 1807
ed9eccbe
DS
1808 return ret;
1809}
1810
1811/*
18e01b24
IA
1812 * COMEDI_LOCK ioctl
1813 * lock subdevice
1814 *
1815 * arg:
1816 * subdevice number
1817 *
1818 * reads:
1819 * nothing
1820 *
1821 * writes:
1822 * nothing
1823 */
c1a6eac1 1824static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
0a85b6f0 1825 void *file)
ed9eccbe
DS
1826{
1827 int ret = 0;
1828 unsigned long flags;
34c43922 1829 struct comedi_subdevice *s;
ed9eccbe
DS
1830
1831 if (arg >= dev->n_subdevices)
1832 return -EINVAL;
b077f2cd 1833 s = &dev->subdevices[arg];
ed9eccbe 1834
5f74ea14 1835 spin_lock_irqsave(&s->spin_lock, flags);
476b8477 1836 if (s->busy || s->lock)
ed9eccbe 1837 ret = -EBUSY;
476b8477 1838 else
ed9eccbe 1839 s->lock = file;
5f74ea14 1840 spin_unlock_irqrestore(&s->spin_lock, flags);
ed9eccbe 1841
ed9eccbe
DS
1842 return ret;
1843}
1844
1845/*
18e01b24
IA
1846 * COMEDI_UNLOCK ioctl
1847 * unlock subdevice
1848 *
1849 * arg:
1850 * subdevice number
1851 *
1852 * reads:
1853 * nothing
1854 *
1855 * writes:
1856 * nothing
1857 */
c1a6eac1 1858static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
0a85b6f0 1859 void *file)
ed9eccbe 1860{
34c43922 1861 struct comedi_subdevice *s;
ed9eccbe
DS
1862
1863 if (arg >= dev->n_subdevices)
1864 return -EINVAL;
b077f2cd 1865 s = &dev->subdevices[arg];
ed9eccbe
DS
1866
1867 if (s->busy)
1868 return -EBUSY;
1869
1870 if (s->lock && s->lock != file)
1871 return -EACCES;
1872
90ac0764 1873 if (s->lock == file)
ed9eccbe 1874 s->lock = NULL;
ed9eccbe
DS
1875
1876 return 0;
1877}
1878
1879/*
18e01b24
IA
1880 * COMEDI_CANCEL ioctl
1881 * cancel asynchronous acquisition
1882 *
1883 * arg:
1884 * subdevice number
1885 *
1886 * reads:
1887 * nothing
1888 *
1889 * writes:
1890 * nothing
1891 */
c1a6eac1 1892static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
0a85b6f0 1893 void *file)
ed9eccbe 1894{
34c43922 1895 struct comedi_subdevice *s;
ed9eccbe
DS
1896
1897 if (arg >= dev->n_subdevices)
1898 return -EINVAL;
b077f2cd 1899 s = &dev->subdevices[arg];
88cc30cf 1900 if (!s->async)
ed9eccbe
DS
1901 return -EINVAL;
1902
ed9eccbe
DS
1903 if (!s->busy)
1904 return 0;
1905
1906 if (s->busy != file)
1907 return -EBUSY;
1908
fe43ec53 1909 return do_cancel(dev, s);
ed9eccbe
DS
1910}
1911
1912/*
18e01b24
IA
1913 * COMEDI_POLL ioctl
1914 * instructs driver to synchronize buffers
1915 *
1916 * arg:
1917 * subdevice number
1918 *
1919 * reads:
1920 * nothing
1921 *
1922 * writes:
1923 * nothing
1924 */
c1a6eac1 1925static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
0a85b6f0 1926 void *file)
ed9eccbe 1927{
34c43922 1928 struct comedi_subdevice *s;
ed9eccbe
DS
1929
1930 if (arg >= dev->n_subdevices)
1931 return -EINVAL;
b077f2cd 1932 s = &dev->subdevices[arg];
ed9eccbe 1933
ed9eccbe
DS
1934 if (!s->busy)
1935 return 0;
1936
1937 if (s->busy != file)
1938 return -EBUSY;
1939
1940 if (s->poll)
1941 return s->poll(dev, s);
1942
1943 return -EINVAL;
1944}
1945
c299a678
IA
1946/*
1947 * COMEDI_SETRSUBD ioctl
1948 * sets the current "read" subdevice on a per-file basis
1949 *
1950 * arg:
1951 * subdevice number
1952 *
1953 * reads:
1954 * nothing
1955 *
1956 * writes:
1957 * nothing
1958 */
1959static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg,
1960 struct file *file)
1961{
1962 struct comedi_file *cfp = file->private_data;
1963 struct comedi_subdevice *s_old, *s_new;
1964
1965 if (arg >= dev->n_subdevices)
1966 return -EINVAL;
1967
1968 s_new = &dev->subdevices[arg];
1969 s_old = comedi_file_read_subdevice(file);
1970 if (s_old == s_new)
1971 return 0; /* no change */
1972
1973 if (!(s_new->subdev_flags & SDF_CMD_READ))
1974 return -EINVAL;
1975
1976 /*
1977 * Check the file isn't still busy handling a "read" command on the
1978 * old subdevice (if any).
1979 */
1980 if (s_old && s_old->busy == file && s_old->async &&
1981 !(s_old->async->cmd.flags & CMDF_WRITE))
1982 return -EBUSY;
1983
1984 ACCESS_ONCE(cfp->read_subdev) = s_new;
1985 return 0;
1986}
1987
1988/*
1989 * COMEDI_SETWSUBD ioctl
1990 * sets the current "write" subdevice on a per-file basis
1991 *
1992 * arg:
1993 * subdevice number
1994 *
1995 * reads:
1996 * nothing
1997 *
1998 * writes:
1999 * nothing
2000 */
2001static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg,
2002 struct file *file)
2003{
2004 struct comedi_file *cfp = file->private_data;
2005 struct comedi_subdevice *s_old, *s_new;
2006
2007 if (arg >= dev->n_subdevices)
2008 return -EINVAL;
2009
2010 s_new = &dev->subdevices[arg];
2011 s_old = comedi_file_write_subdevice(file);
2012 if (s_old == s_new)
2013 return 0; /* no change */
2014
2015 if (!(s_new->subdev_flags & SDF_CMD_WRITE))
2016 return -EINVAL;
2017
2018 /*
2019 * Check the file isn't still busy handling a "write" command on the
2020 * old subdevice (if any).
2021 */
2022 if (s_old && s_old->busy == file && s_old->async &&
2023 (s_old->async->cmd.flags & CMDF_WRITE))
2024 return -EBUSY;
2025
2026 ACCESS_ONCE(cfp->write_subdev) = s_new;
2027 return 0;
2028}
2029
47db6d58
HS
2030static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
2031 unsigned long arg)
2032{
20f083c0
IA
2033 unsigned minor = iminor(file_inode(file));
2034 struct comedi_file *cfp = file->private_data;
2035 struct comedi_device *dev = cfp->dev;
47db6d58
HS
2036 int rc;
2037
47db6d58
HS
2038 mutex_lock(&dev->mutex);
2039
a2aab8b4
IA
2040 /*
2041 * Device config is special, because it must work on
2042 * an unconfigured device.
2043 */
47db6d58 2044 if (cmd == COMEDI_DEVCONFIG) {
754ab5c0
IA
2045 if (minor >= COMEDI_NUM_BOARD_MINORS) {
2046 /* Device config not appropriate on non-board minors. */
2047 rc = -ENOTTY;
2048 goto done;
2049 }
47db6d58
HS
2050 rc = do_devconfig_ioctl(dev,
2051 (struct comedi_devconfig __user *)arg);
8ab4ed6e
IA
2052 if (rc == 0) {
2053 if (arg == 0 &&
2054 dev->minor >= comedi_num_legacy_minors) {
a2aab8b4
IA
2055 /*
2056 * Successfully unconfigured a dynamically
2057 * allocated device. Try and remove it.
2058 */
db210da2 2059 if (comedi_clear_board_dev(dev)) {
8ab4ed6e 2060 mutex_unlock(&dev->mutex);
cb6b79de 2061 comedi_free_board_dev(dev);
8ab4ed6e
IA
2062 return rc;
2063 }
2064 }
2065 }
47db6d58
HS
2066 goto done;
2067 }
2068
2069 if (!dev->attached) {
272850f0 2070 dev_dbg(dev->class_dev, "no driver attached\n");
47db6d58
HS
2071 rc = -ENODEV;
2072 goto done;
2073 }
2074
2075 switch (cmd) {
2076 case COMEDI_BUFCONFIG:
2077 rc = do_bufconfig_ioctl(dev,
2078 (struct comedi_bufconfig __user *)arg);
2079 break;
2080 case COMEDI_DEVINFO:
2081 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
2082 file);
2083 break;
2084 case COMEDI_SUBDINFO:
2085 rc = do_subdinfo_ioctl(dev,
2086 (struct comedi_subdinfo __user *)arg,
2087 file);
2088 break;
2089 case COMEDI_CHANINFO:
2090 rc = do_chaninfo_ioctl(dev, (void __user *)arg);
2091 break;
2092 case COMEDI_RANGEINFO:
2093 rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
2094 break;
2095 case COMEDI_BUFINFO:
2096 rc = do_bufinfo_ioctl(dev,
2097 (struct comedi_bufinfo __user *)arg,
2098 file);
2099 break;
2100 case COMEDI_LOCK:
2101 rc = do_lock_ioctl(dev, arg, file);
2102 break;
2103 case COMEDI_UNLOCK:
2104 rc = do_unlock_ioctl(dev, arg, file);
2105 break;
2106 case COMEDI_CANCEL:
2107 rc = do_cancel_ioctl(dev, arg, file);
2108 break;
2109 case COMEDI_CMD:
2110 rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
2111 break;
2112 case COMEDI_CMDTEST:
2113 rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
2114 file);
2115 break;
2116 case COMEDI_INSNLIST:
2117 rc = do_insnlist_ioctl(dev,
2118 (struct comedi_insnlist __user *)arg,
2119 file);
2120 break;
2121 case COMEDI_INSN:
2122 rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
2123 file);
2124 break;
2125 case COMEDI_POLL:
2126 rc = do_poll_ioctl(dev, arg, file);
2127 break;
c299a678
IA
2128 case COMEDI_SETRSUBD:
2129 rc = do_setrsubd_ioctl(dev, arg, file);
2130 break;
2131 case COMEDI_SETWSUBD:
2132 rc = do_setwsubd_ioctl(dev, arg, file);
2133 break;
47db6d58
HS
2134 default:
2135 rc = -ENOTTY;
2136 break;
2137 }
2138
2139done:
2140 mutex_unlock(&dev->mutex);
2141 return rc;
2142}
2143
df30b21c
FV
2144static void comedi_vm_open(struct vm_area_struct *area)
2145{
af93da31 2146 struct comedi_buf_map *bm;
df30b21c 2147
af93da31
IA
2148 bm = area->vm_private_data;
2149 comedi_buf_map_get(bm);
df30b21c
FV
2150}
2151
2152static void comedi_vm_close(struct vm_area_struct *area)
ed9eccbe 2153{
af93da31 2154 struct comedi_buf_map *bm;
ed9eccbe 2155
af93da31
IA
2156 bm = area->vm_private_data;
2157 comedi_buf_map_put(bm);
ed9eccbe
DS
2158}
2159
2160static struct vm_operations_struct comedi_vm_ops = {
df30b21c
FV
2161 .open = comedi_vm_open,
2162 .close = comedi_vm_close,
ed9eccbe
DS
2163};
2164
2165static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
2166{
20f083c0
IA
2167 struct comedi_file *cfp = file->private_data;
2168 struct comedi_device *dev = cfp->dev;
a52840a9
HS
2169 struct comedi_subdevice *s;
2170 struct comedi_async *async;
b34aa86f 2171 struct comedi_buf_map *bm = NULL;
ed9eccbe
DS
2172 unsigned long start = vma->vm_start;
2173 unsigned long size;
2174 int n_pages;
2175 int i;
2176 int retval;
3ffab428 2177
b34aa86f
IA
2178 /*
2179 * 'trylock' avoids circular dependency with current->mm->mmap_sem
2180 * and down-reading &dev->attach_lock should normally succeed without
2181 * contention unless the device is in the process of being attached
2182 * or detached.
2183 */
2184 if (!down_read_trylock(&dev->attach_lock))
2185 return -EAGAIN;
a52840a9 2186
ed9eccbe 2187 if (!dev->attached) {
272850f0 2188 dev_dbg(dev->class_dev, "no driver attached\n");
ed9eccbe
DS
2189 retval = -ENODEV;
2190 goto done;
2191 }
a52840a9 2192
476b8477 2193 if (vma->vm_flags & VM_WRITE)
20f083c0 2194 s = comedi_file_write_subdevice(file);
476b8477 2195 else
20f083c0 2196 s = comedi_file_read_subdevice(file);
a52840a9 2197 if (!s) {
ed9eccbe
DS
2198 retval = -EINVAL;
2199 goto done;
2200 }
a52840a9 2201
ed9eccbe 2202 async = s->async;
a52840a9 2203 if (!async) {
ed9eccbe
DS
2204 retval = -EINVAL;
2205 goto done;
2206 }
2207
2208 if (vma->vm_pgoff != 0) {
272850f0 2209 dev_dbg(dev->class_dev, "mmap() offset must be 0.\n");
ed9eccbe
DS
2210 retval = -EINVAL;
2211 goto done;
2212 }
2213
2214 size = vma->vm_end - vma->vm_start;
2215 if (size > async->prealloc_bufsz) {
2216 retval = -EFAULT;
2217 goto done;
2218 }
2219 if (size & (~PAGE_MASK)) {
2220 retval = -EFAULT;
2221 goto done;
2222 }
2223
2224 n_pages = size >> PAGE_SHIFT;
b34aa86f
IA
2225
2226 /* get reference to current buf map (if any) */
2227 bm = comedi_buf_map_from_subdev_get(s);
af93da31
IA
2228 if (!bm || n_pages > bm->n_pages) {
2229 retval = -EINVAL;
2230 goto done;
2231 }
ed9eccbe 2232 for (i = 0; i < n_pages; ++i) {
af93da31 2233 struct comedi_buf_page *buf = &bm->page_list[i];
a52840a9 2234
ed9eccbe 2235 if (remap_pfn_range(vma, start,
a52840a9
HS
2236 page_to_pfn(virt_to_page(buf->virt_addr)),
2237 PAGE_SIZE, PAGE_SHARED)) {
ed9eccbe
DS
2238 retval = -EAGAIN;
2239 goto done;
2240 }
2241 start += PAGE_SIZE;
2242 }
2243
2244 vma->vm_ops = &comedi_vm_ops;
af93da31 2245 vma->vm_private_data = bm;
ed9eccbe 2246
af93da31 2247 vma->vm_ops->open(vma);
ed9eccbe
DS
2248
2249 retval = 0;
476b8477 2250done:
b34aa86f
IA
2251 up_read(&dev->attach_lock);
2252 comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
ed9eccbe
DS
2253 return retval;
2254}
2255
1ae5062a 2256static unsigned int comedi_poll(struct file *file, poll_table *wait)
ed9eccbe
DS
2257{
2258 unsigned int mask = 0;
20f083c0
IA
2259 struct comedi_file *cfp = file->private_data;
2260 struct comedi_device *dev = cfp->dev;
ca081b1d 2261 struct comedi_subdevice *s;
3ffab428 2262
ed9eccbe 2263 mutex_lock(&dev->mutex);
ca081b1d 2264
ed9eccbe 2265 if (!dev->attached) {
272850f0 2266 dev_dbg(dev->class_dev, "no driver attached\n");
ca081b1d 2267 goto done;
ed9eccbe
DS
2268 }
2269
20f083c0 2270 s = comedi_file_read_subdevice(file);
cc400e18 2271 if (s && s->async) {
ca081b1d 2272 poll_wait(file, &s->async->wait_head, wait);
f0124630 2273 if (!s->busy || !comedi_is_subdevice_running(s) ||
662c722b 2274 (s->async->cmd.flags & CMDF_WRITE) ||
e9edef3a 2275 comedi_buf_read_n_available(s) > 0)
ed9eccbe 2276 mask |= POLLIN | POLLRDNORM;
ed9eccbe 2277 }
ca081b1d 2278
20f083c0 2279 s = comedi_file_write_subdevice(file);
cc400e18 2280 if (s && s->async) {
c39e050d 2281 unsigned int bps = comedi_bytes_per_sample(s);
ca081b1d
HS
2282
2283 poll_wait(file, &s->async->wait_head, wait);
24e894bb 2284 comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
f0124630 2285 if (!s->busy || !comedi_is_subdevice_running(s) ||
662c722b 2286 !(s->async->cmd.flags & CMDF_WRITE) ||
0f1f34e8 2287 comedi_buf_write_n_allocated(s) >= bps)
ed9eccbe 2288 mask |= POLLOUT | POLLWRNORM;
ed9eccbe
DS
2289 }
2290
ca081b1d 2291done:
ed9eccbe
DS
2292 mutex_unlock(&dev->mutex);
2293 return mask;
2294}
2295
92d0127c
GKH
2296static ssize_t comedi_write(struct file *file, const char __user *buf,
2297 size_t nbytes, loff_t *offset)
ed9eccbe 2298{
34c43922 2299 struct comedi_subdevice *s;
d163679c 2300 struct comedi_async *async;
ed9eccbe
DS
2301 int n, m, count = 0, retval = 0;
2302 DECLARE_WAITQUEUE(wait, current);
20f083c0
IA
2303 struct comedi_file *cfp = file->private_data;
2304 struct comedi_device *dev = cfp->dev;
9329f139
IA
2305 bool on_wait_queue = false;
2306 bool attach_locked;
2307 unsigned int old_detach_count;
3ffab428 2308
9329f139
IA
2309 /* Protect against device detachment during operation. */
2310 down_read(&dev->attach_lock);
2311 attach_locked = true;
2312 old_detach_count = dev->detach_count;
2313
ed9eccbe 2314 if (!dev->attached) {
272850f0 2315 dev_dbg(dev->class_dev, "no driver attached\n");
9329f139
IA
2316 retval = -ENODEV;
2317 goto out;
ed9eccbe
DS
2318 }
2319
20f083c0 2320 s = comedi_file_write_subdevice(file);
9329f139
IA
2321 if (!s || !s->async) {
2322 retval = -EIO;
2323 goto out;
2324 }
2714b019 2325
ed9eccbe
DS
2326 async = s->async;
2327
2714b019 2328 if (!s->busy || !nbytes)
9329f139
IA
2329 goto out;
2330 if (s->busy != file) {
2331 retval = -EACCES;
2332 goto out;
2333 }
f7398509
IA
2334 if (!(async->cmd.flags & CMDF_WRITE)) {
2335 retval = -EINVAL;
2336 goto out;
2337 }
2714b019 2338
ed9eccbe 2339 add_wait_queue(&async->wait_head, &wait);
9329f139 2340 on_wait_queue = true;
ed9eccbe 2341 while (nbytes > 0 && !retval) {
b183a836
IA
2342 unsigned runflags;
2343
ed9eccbe
DS
2344 set_current_state(TASK_INTERRUPTIBLE);
2345
b183a836
IA
2346 runflags = comedi_get_subdevice_runflags(s);
2347 if (!comedi_is_runflags_running(runflags)) {
d2611540 2348 if (count == 0) {
9329f139
IA
2349 struct comedi_subdevice *new_s;
2350
b183a836 2351 if (comedi_is_runflags_in_error(runflags))
d2611540 2352 retval = -EPIPE;
c098c21a 2353 else
d2611540 2354 retval = 0;
9329f139
IA
2355 /*
2356 * To avoid deadlock, cannot acquire dev->mutex
2357 * while dev->attach_lock is held. Need to
2358 * remove task from the async wait queue before
2359 * releasing dev->attach_lock, as it might not
2360 * be valid afterwards.
2361 */
2362 remove_wait_queue(&async->wait_head, &wait);
2363 on_wait_queue = false;
2364 up_read(&dev->attach_lock);
2365 attach_locked = false;
2366 mutex_lock(&dev->mutex);
2367 /*
2368 * Become non-busy unless things have changed
2369 * behind our back. Checking dev->detach_count
2370 * is unchanged ought to be sufficient (unless
2371 * there have been 2**32 detaches in the
2372 * meantime!), but check the subdevice pointer
2373 * as well just in case.
2374 */
20f083c0 2375 new_s = comedi_file_write_subdevice(file);
9329f139
IA
2376 if (dev->attached &&
2377 old_detach_count == dev->detach_count &&
2378 s == new_s && new_s->async == async)
2379 do_become_nonbusy(dev, s);
4b18f08b 2380 mutex_unlock(&dev->mutex);
d2611540
IA
2381 }
2382 break;
2383 }
2384
ed9eccbe
DS
2385 n = nbytes;
2386
2387 m = n;
476b8477 2388 if (async->buf_write_ptr + m > async->prealloc_bufsz)
ed9eccbe 2389 m = async->prealloc_bufsz - async->buf_write_ptr;
24e894bb 2390 comedi_buf_write_alloc(s, async->prealloc_bufsz);
0f1f34e8
IA
2391 if (m > comedi_buf_write_n_allocated(s))
2392 m = comedi_buf_write_n_allocated(s);
ed9eccbe
DS
2393 if (m < n)
2394 n = m;
2395
2396 if (n == 0) {
ed9eccbe
DS
2397 if (file->f_flags & O_NONBLOCK) {
2398 retval = -EAGAIN;
2399 break;
2400 }
6a9ce6b6 2401 schedule();
ed9eccbe
DS
2402 if (signal_pending(current)) {
2403 retval = -ERESTARTSYS;
2404 break;
2405 }
476b8477 2406 if (!s->busy)
ed9eccbe 2407 break;
ed9eccbe
DS
2408 if (s->busy != file) {
2409 retval = -EACCES;
2410 break;
2411 }
f7398509
IA
2412 if (!(async->cmd.flags & CMDF_WRITE)) {
2413 retval = -EINVAL;
2414 break;
2415 }
ed9eccbe
DS
2416 continue;
2417 }
2418
2419 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
476b8477 2420 buf, n);
ed9eccbe
DS
2421 if (m) {
2422 n -= m;
2423 retval = -EFAULT;
2424 }
940dd35d 2425 comedi_buf_write_free(s, n);
ed9eccbe
DS
2426
2427 count += n;
2428 nbytes -= n;
2429
2430 buf += n;
2431 break; /* makes device work like a pipe */
2432 }
9329f139
IA
2433out:
2434 if (on_wait_queue)
2435 remove_wait_queue(&async->wait_head, &wait);
ed9eccbe 2436 set_current_state(TASK_RUNNING);
9329f139
IA
2437 if (attach_locked)
2438 up_read(&dev->attach_lock);
ed9eccbe 2439
476b8477 2440 return count ? count : retval;
ed9eccbe
DS
2441}
2442
92d0127c 2443static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
36efbacd 2444 loff_t *offset)
ed9eccbe 2445{
34c43922 2446 struct comedi_subdevice *s;
d163679c 2447 struct comedi_async *async;
ed9eccbe
DS
2448 int n, m, count = 0, retval = 0;
2449 DECLARE_WAITQUEUE(wait, current);
20f083c0
IA
2450 struct comedi_file *cfp = file->private_data;
2451 struct comedi_device *dev = cfp->dev;
45c2bc55
IA
2452 unsigned int old_detach_count;
2453 bool become_nonbusy = false;
2454 bool attach_locked;
3ffab428 2455
45c2bc55
IA
2456 /* Protect against device detachment during operation. */
2457 down_read(&dev->attach_lock);
2458 attach_locked = true;
2459 old_detach_count = dev->detach_count;
2460
ed9eccbe 2461 if (!dev->attached) {
272850f0 2462 dev_dbg(dev->class_dev, "no driver attached\n");
45c2bc55
IA
2463 retval = -ENODEV;
2464 goto out;
ed9eccbe
DS
2465 }
2466
20f083c0 2467 s = comedi_file_read_subdevice(file);
45c2bc55
IA
2468 if (!s || !s->async) {
2469 retval = -EIO;
2470 goto out;
2471 }
5c87fef5 2472
ed9eccbe 2473 async = s->async;
5c87fef5 2474 if (!s->busy || !nbytes)
45c2bc55
IA
2475 goto out;
2476 if (s->busy != file) {
2477 retval = -EACCES;
2478 goto out;
2479 }
f025ab9e
IA
2480 if (async->cmd.flags & CMDF_WRITE) {
2481 retval = -EINVAL;
2482 goto out;
2483 }
ed9eccbe
DS
2484
2485 add_wait_queue(&async->wait_head, &wait);
2486 while (nbytes > 0 && !retval) {
2487 set_current_state(TASK_INTERRUPTIBLE);
2488
2489 n = nbytes;
2490
e9edef3a 2491 m = comedi_buf_read_n_available(s);
476b8477 2492 if (async->buf_read_ptr + m > async->prealloc_bufsz)
ed9eccbe 2493 m = async->prealloc_bufsz - async->buf_read_ptr;
ed9eccbe
DS
2494 if (m < n)
2495 n = m;
2496
2497 if (n == 0) {
b183a836
IA
2498 unsigned runflags = comedi_get_subdevice_runflags(s);
2499
2500 if (!comedi_is_runflags_running(runflags)) {
2501 if (comedi_is_runflags_in_error(runflags))
ed9eccbe 2502 retval = -EPIPE;
c098c21a 2503 else
ed9eccbe 2504 retval = 0;
45c2bc55 2505 become_nonbusy = true;
ed9eccbe
DS
2506 break;
2507 }
2508 if (file->f_flags & O_NONBLOCK) {
2509 retval = -EAGAIN;
2510 break;
2511 }
6a9ce6b6 2512 schedule();
ed9eccbe
DS
2513 if (signal_pending(current)) {
2514 retval = -ERESTARTSYS;
2515 break;
2516 }
ed9eccbe
DS
2517 if (!s->busy) {
2518 retval = 0;
2519 break;
2520 }
2521 if (s->busy != file) {
2522 retval = -EACCES;
2523 break;
2524 }
f025ab9e
IA
2525 if (async->cmd.flags & CMDF_WRITE) {
2526 retval = -EINVAL;
2527 break;
2528 }
ed9eccbe
DS
2529 continue;
2530 }
2531 m = copy_to_user(buf, async->prealloc_buf +
476b8477 2532 async->buf_read_ptr, n);
ed9eccbe
DS
2533 if (m) {
2534 n -= m;
2535 retval = -EFAULT;
2536 }
2537
d13be55a 2538 comedi_buf_read_alloc(s, n);
f1df8662 2539 comedi_buf_read_free(s, n);
ed9eccbe
DS
2540
2541 count += n;
2542 nbytes -= n;
2543
2544 buf += n;
2545 break; /* makes device work like a pipe */
2546 }
45c2bc55
IA
2547 remove_wait_queue(&async->wait_head, &wait);
2548 set_current_state(TASK_RUNNING);
2549 if (become_nonbusy || comedi_is_subdevice_idle(s)) {
2550 struct comedi_subdevice *new_s;
2551
2552 /*
2553 * To avoid deadlock, cannot acquire dev->mutex
2554 * while dev->attach_lock is held.
2555 */
2556 up_read(&dev->attach_lock);
2557 attach_locked = false;
4b18f08b 2558 mutex_lock(&dev->mutex);
45c2bc55
IA
2559 /*
2560 * Check device hasn't become detached behind our back.
2561 * Checking dev->detach_count is unchanged ought to be
2562 * sufficient (unless there have been 2**32 detaches in the
2563 * meantime!), but check the subdevice pointer as well just in
2564 * case.
2565 */
20f083c0 2566 new_s = comedi_file_read_subdevice(file);
45c2bc55
IA
2567 if (dev->attached && old_detach_count == dev->detach_count &&
2568 s == new_s && new_s->async == async) {
f4f3f7cf 2569 if (become_nonbusy || comedi_buf_n_bytes_ready(s) == 0)
45c2bc55
IA
2570 do_become_nonbusy(dev, s);
2571 }
4b18f08b 2572 mutex_unlock(&dev->mutex);
ed9eccbe 2573 }
45c2bc55
IA
2574out:
2575 if (attach_locked)
2576 up_read(&dev->attach_lock);
ed9eccbe 2577
476b8477 2578 return count ? count : retval;
ed9eccbe
DS
2579}
2580
ed9eccbe
DS
2581static int comedi_open(struct inode *inode, struct file *file)
2582{
ed9eccbe 2583 const unsigned minor = iminor(inode);
20f083c0 2584 struct comedi_file *cfp;
fc406986
IA
2585 struct comedi_device *dev = comedi_dev_get_from_minor(minor);
2586 int rc;
97920071 2587
4da5fa9a 2588 if (!dev) {
272850f0 2589 pr_debug("invalid minor number\n");
ed9eccbe
DS
2590 return -ENODEV;
2591 }
2592
20f083c0
IA
2593 cfp = kzalloc(sizeof(*cfp), GFP_KERNEL);
2594 if (!cfp)
2595 return -ENOMEM;
2596
2597 cfp->dev = dev;
2598
ed9eccbe 2599 mutex_lock(&dev->mutex);
0e0d311e
IA
2600 if (!dev->attached && !capable(CAP_SYS_ADMIN)) {
2601 dev_dbg(dev->class_dev, "not attached and not CAP_SYS_ADMIN\n");
fc406986
IA
2602 rc = -ENODEV;
2603 goto out;
ed9eccbe 2604 }
1363e4fb 2605 if (dev->attached && dev->use_count == 0) {
ed9eccbe 2606 if (!try_module_get(dev->driver->module)) {
90e6f51d 2607 rc = -ENXIO;
fc406986 2608 goto out;
ed9eccbe 2609 }
1363e4fb
IA
2610 if (dev->open) {
2611 rc = dev->open(dev);
2612 if (rc < 0) {
2613 module_put(dev->driver->module);
2614 goto out;
2615 }
3c17ba07
IA
2616 }
2617 }
ed9eccbe
DS
2618
2619 dev->use_count++;
20f083c0
IA
2620 file->private_data = cfp;
2621 comedi_file_reset(file);
fc406986 2622 rc = 0;
ed9eccbe 2623
fc406986 2624out:
a5011a26 2625 mutex_unlock(&dev->mutex);
20f083c0 2626 if (rc) {
fc406986 2627 comedi_dev_put(dev);
20f083c0
IA
2628 kfree(cfp);
2629 }
fc406986 2630 return rc;
ed9eccbe
DS
2631}
2632
2aae0076
HS
2633static int comedi_fasync(int fd, struct file *file, int on)
2634{
20f083c0
IA
2635 struct comedi_file *cfp = file->private_data;
2636 struct comedi_device *dev = cfp->dev;
2aae0076
HS
2637
2638 return fasync_helper(fd, file, on, &dev->async_queue);
2639}
2640
a5011a26 2641static int comedi_close(struct inode *inode, struct file *file)
ed9eccbe 2642{
20f083c0
IA
2643 struct comedi_file *cfp = file->private_data;
2644 struct comedi_device *dev = cfp->dev;
a5011a26 2645 struct comedi_subdevice *s = NULL;
ed9eccbe
DS
2646 int i;
2647
a5011a26
HS
2648 mutex_lock(&dev->mutex);
2649
2650 if (dev->subdevices) {
2651 for (i = 0; i < dev->n_subdevices; i++) {
b077f2cd 2652 s = &dev->subdevices[i];
a5011a26
HS
2653
2654 if (s->busy == file)
2655 do_cancel(dev, s);
2656 if (s->lock == file)
2657 s->lock = NULL;
2658 }
ed9eccbe 2659 }
1363e4fb
IA
2660 if (dev->attached && dev->use_count == 1) {
2661 if (dev->close)
2662 dev->close(dev);
a5011a26 2663 module_put(dev->driver->module);
1363e4fb 2664 }
a5011a26
HS
2665
2666 dev->use_count--;
2667
2668 mutex_unlock(&dev->mutex);
fc406986 2669 comedi_dev_put(dev);
20f083c0 2670 kfree(cfp);
a5011a26 2671
ed9eccbe
DS
2672 return 0;
2673}
2674
8cb8aad7 2675static const struct file_operations comedi_fops = {
a5011a26
HS
2676 .owner = THIS_MODULE,
2677 .unlocked_ioctl = comedi_unlocked_ioctl,
2678 .compat_ioctl = comedi_compat_ioctl,
2679 .open = comedi_open,
2680 .release = comedi_close,
2681 .read = comedi_read,
2682 .write = comedi_write,
2683 .mmap = comedi_mmap,
2684 .poll = comedi_poll,
2685 .fasync = comedi_fasync,
2686 .llseek = noop_llseek,
2687};
2688
dd630cde
IA
2689/**
2690 * comedi_event - handle events for asynchronous comedi command
2691 * @dev: comedi_device struct
2692 * @s: comedi_subdevice struct associated with dev
2693 * Context: interrupt (usually), s->spin_lock spin-lock not held
2694 *
2695 * If an asynchronous comedi command is active on the subdevice, process
2696 * any COMEDI_CB_... event flags that have been set, usually by an
2697 * interrupt handler. These may change the run state of the asynchronous
2698 * command, wake a task, and/or send a SIGIO signal.
2699 */
a5011a26 2700void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
883db3d9 2701{
a5011a26 2702 struct comedi_async *async = s->async;
ef4b4b27
IA
2703 unsigned int events;
2704 int si_code = 0;
2705 unsigned long flags;
2706
2707 spin_lock_irqsave(&s->spin_lock, flags);
883db3d9 2708
ef4b4b27 2709 events = async->events;
922d9ced 2710 async->events = 0;
ef4b4b27
IA
2711 if (!__comedi_is_subdevice_running(s)) {
2712 spin_unlock_irqrestore(&s->spin_lock, flags);
a5011a26 2713 return;
ef4b4b27 2714 }
a5011a26 2715
922d9ced 2716 if (events & COMEDI_CB_CANCEL_MASK)
ef4b4b27 2717 __comedi_clear_subdevice_runflags(s, COMEDI_SRF_RUNNING);
781f933c
HS
2718
2719 /*
ef4b4b27
IA
2720 * Remember if an error event has occurred, so an error can be
2721 * returned the next time the user does a read() or write().
781f933c 2722 */
ef4b4b27
IA
2723 if (events & COMEDI_CB_ERROR_MASK)
2724 __comedi_set_subdevice_runflags(s, COMEDI_SRF_ERROR);
883db3d9 2725
922d9ced 2726 if (async->cb_mask & events) {
c265be01 2727 wake_up_interruptible(&async->wait_head);
aa33122f 2728 si_code = async->cmd.flags & CMDF_WRITE ? POLL_OUT : POLL_IN;
a5011a26 2729 }
ef4b4b27
IA
2730
2731 spin_unlock_irqrestore(&s->spin_lock, flags);
2732
2733 if (si_code)
2734 kill_fasync(&dev->async_queue, SIGIO, si_code);
883db3d9 2735}
5660e742 2736EXPORT_SYMBOL_GPL(comedi_event);
883db3d9 2737
07778393 2738/* Note: the ->mutex is pre-locked on successful return */
7638ffcb 2739struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
a5011a26 2740{
7638ffcb 2741 struct comedi_device *dev;
a5011a26
HS
2742 struct device *csdev;
2743 unsigned i;
a5011a26 2744
36efbacd 2745 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
88cc30cf 2746 if (!dev)
7638ffcb 2747 return ERR_PTR(-ENOMEM);
7638ffcb 2748 comedi_device_init(dev);
db2e3487 2749 comedi_set_hw_dev(dev, hardware_device);
07778393 2750 mutex_lock(&dev->mutex);
5b7dba1b 2751 mutex_lock(&comedi_board_minor_table_lock);
38b9722a
IA
2752 for (i = hardware_device ? comedi_num_legacy_minors : 0;
2753 i < COMEDI_NUM_BOARD_MINORS; ++i) {
88cc30cf 2754 if (!comedi_board_minor_table[i]) {
cb6b79de 2755 comedi_board_minor_table[i] = dev;
a5011a26
HS
2756 break;
2757 }
2758 }
5b7dba1b 2759 mutex_unlock(&comedi_board_minor_table_lock);
a5011a26 2760 if (i == COMEDI_NUM_BOARD_MINORS) {
07778393 2761 mutex_unlock(&dev->mutex);
7638ffcb 2762 comedi_device_cleanup(dev);
5b13ed94 2763 comedi_dev_put(dev);
a112eab4
HM
2764 dev_err(hardware_device,
2765 "ran out of minor numbers for board device files\n");
7638ffcb 2766 return ERR_PTR(-EBUSY);
a5011a26 2767 }
7638ffcb 2768 dev->minor = i;
a5011a26
HS
2769 csdev = device_create(comedi_class, hardware_device,
2770 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2771 if (!IS_ERR(csdev))
8f988d87 2772 dev->class_dev = get_device(csdev);
883db3d9 2773
07778393 2774 /* Note: dev->mutex needs to be unlocked by the caller. */
7638ffcb 2775 return dev;
883db3d9
FMH
2776}
2777
70f30c37 2778static void comedi_free_board_minor(unsigned minor)
24fb134d
IA
2779{
2780 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
cb6b79de 2781 comedi_free_board_dev(comedi_clear_board_minor(minor));
24fb134d
IA
2782}
2783
3346b798 2784void comedi_release_hardware_device(struct device *hardware_device)
883db3d9 2785{
a5011a26 2786 int minor;
cb6b79de 2787 struct comedi_device *dev;
883db3d9 2788
38b9722a
IA
2789 for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
2790 minor++) {
5b7dba1b 2791 mutex_lock(&comedi_board_minor_table_lock);
cb6b79de
IA
2792 dev = comedi_board_minor_table[minor];
2793 if (dev && dev->hw_dev == hardware_device) {
5b7dba1b
IA
2794 comedi_board_minor_table[minor] = NULL;
2795 mutex_unlock(&comedi_board_minor_table_lock);
cb6b79de 2796 comedi_free_board_dev(dev);
3346b798 2797 break;
a5011a26 2798 }
5b7dba1b 2799 mutex_unlock(&comedi_board_minor_table_lock);
883db3d9 2800 }
883db3d9
FMH
2801}
2802
f65cc544 2803int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
883db3d9 2804{
f65cc544 2805 struct comedi_device *dev = s->device;
a5011a26
HS
2806 struct device *csdev;
2807 unsigned i;
883db3d9 2808
5b7dba1b
IA
2809 mutex_lock(&comedi_subdevice_minor_table_lock);
2810 for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
88cc30cf 2811 if (!comedi_subdevice_minor_table[i]) {
bd5b4173 2812 comedi_subdevice_minor_table[i] = s;
a5011a26
HS
2813 break;
2814 }
2815 }
5b7dba1b
IA
2816 mutex_unlock(&comedi_subdevice_minor_table_lock);
2817 if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
a112eab4
HM
2818 dev_err(dev->class_dev,
2819 "ran out of minor numbers for subdevice files\n");
a5011a26
HS
2820 return -EBUSY;
2821 }
5b7dba1b 2822 i += COMEDI_NUM_BOARD_MINORS;
a5011a26
HS
2823 s->minor = i;
2824 csdev = device_create(comedi_class, dev->class_dev,
2825 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
90a35c15 2826 dev->minor, s->index);
a5011a26
HS
2827 if (!IS_ERR(csdev))
2828 s->class_dev = csdev;
883db3d9 2829
da718546 2830 return 0;
883db3d9
FMH
2831}
2832
a5011a26 2833void comedi_free_subdevice_minor(struct comedi_subdevice *s)
883db3d9 2834{
0fcc9d48 2835 unsigned int i;
883db3d9 2836
88cc30cf 2837 if (!s)
a5011a26 2838 return;
5104a898
HS
2839 if (s->minor < COMEDI_NUM_BOARD_MINORS ||
2840 s->minor >= COMEDI_NUM_MINORS)
a5011a26 2841 return;
883db3d9 2842
0fcc9d48
IA
2843 i = s->minor - COMEDI_NUM_BOARD_MINORS;
2844 mutex_lock(&comedi_subdevice_minor_table_lock);
bd5b4173
IA
2845 if (s == comedi_subdevice_minor_table[i])
2846 comedi_subdevice_minor_table[i] = NULL;
0fcc9d48 2847 mutex_unlock(&comedi_subdevice_minor_table_lock);
a5011a26
HS
2848 if (s->class_dev) {
2849 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2850 s->class_dev = NULL;
883db3d9 2851 }
883db3d9 2852}
a5787824 2853
682b9119 2854static void comedi_cleanup_board_minors(void)
76cca89f
HS
2855{
2856 unsigned i;
2857
682b9119 2858 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
76cca89f
HS
2859 comedi_free_board_minor(i);
2860}
2861
91fa0b0c
HS
2862static int __init comedi_init(void)
2863{
2864 int i;
2865 int retval;
2866
c2ad078b 2867 pr_info("version " COMEDI_RELEASE " - http://www.comedi.org\n");
91fa0b0c
HS
2868
2869 if (comedi_num_legacy_minors < 0 ||
2870 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
c2ad078b 2871 pr_err("invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n",
91fa0b0c
HS
2872 COMEDI_NUM_BOARD_MINORS);
2873 return -EINVAL;
2874 }
2875
91fa0b0c
HS
2876 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2877 COMEDI_NUM_MINORS, "comedi");
2878 if (retval)
2879 return -EIO;
2880 cdev_init(&comedi_cdev, &comedi_fops);
2881 comedi_cdev.owner = THIS_MODULE;
a5bde3a1
AP
2882
2883 retval = kobject_set_name(&comedi_cdev.kobj, "comedi");
2884 if (retval) {
2885 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2886 COMEDI_NUM_MINORS);
2887 return retval;
2888 }
2889
91fa0b0c
HS
2890 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2891 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2892 COMEDI_NUM_MINORS);
2893 return -EIO;
2894 }
2895 comedi_class = class_create(THIS_MODULE, "comedi");
2896 if (IS_ERR(comedi_class)) {
c2ad078b 2897 pr_err("failed to create class\n");
91fa0b0c
HS
2898 cdev_del(&comedi_cdev);
2899 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2900 COMEDI_NUM_MINORS);
2901 return PTR_ERR(comedi_class);
2902 }
2903
e56341ad 2904 comedi_class->dev_groups = comedi_dev_groups;
91fa0b0c
HS
2905
2906 /* XXX requires /proc interface */
2907 comedi_proc_init();
2908
2909 /* create devices files for legacy/manual use */
2910 for (i = 0; i < comedi_num_legacy_minors; i++) {
7638ffcb 2911 struct comedi_device *dev;
4bac39f6 2912
7638ffcb
IA
2913 dev = comedi_alloc_board_minor(NULL);
2914 if (IS_ERR(dev)) {
682b9119 2915 comedi_cleanup_board_minors();
91fa0b0c
HS
2916 cdev_del(&comedi_cdev);
2917 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2918 COMEDI_NUM_MINORS);
7638ffcb 2919 return PTR_ERR(dev);
91fa0b0c 2920 }
cb3aadae
KH
2921 /* comedi_alloc_board_minor() locked the mutex */
2922 mutex_unlock(&dev->mutex);
91fa0b0c
HS
2923 }
2924
2925 return 0;
2926}
2927module_init(comedi_init);
2928
2929static void __exit comedi_cleanup(void)
2930{
682b9119 2931 comedi_cleanup_board_minors();
91fa0b0c
HS
2932 class_destroy(comedi_class);
2933 cdev_del(&comedi_cdev);
2934 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2935
2936 comedi_proc_cleanup();
2937}
2938module_exit(comedi_cleanup);
2939
a5787824
HS
2940MODULE_AUTHOR("http://www.comedi.org");
2941MODULE_DESCRIPTION("Comedi core module");
2942MODULE_LICENSE("GPL");
This page took 1.609138 seconds and 5 git commands to generate.