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