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