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