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