staging: comedi: comedi_fops: introduce comedi_dev_from_minor()
[deliverable/linux.git] / drivers / staging / comedi / comedi_fops.c
CommitLineData
ed9eccbe
DS
1/*
2 comedi/comedi_fops.c
3 comedi kernel module
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23
24#undef DEBUG
25
ed9eccbe
DS
26#include "comedi_compat32.h"
27
28#include <linux/module.h>
29#include <linux/errno.h>
30#include <linux/kernel.h>
31#include <linux/sched.h>
32#include <linux/fcntl.h>
33#include <linux/delay.h>
34#include <linux/ioport.h>
35#include <linux/mm.h>
36#include <linux/slab.h>
37#include <linux/kmod.h>
38#include <linux/poll.h>
39#include <linux/init.h>
40#include <linux/device.h>
41#include <linux/vmalloc.h>
42#include <linux/fs.h>
43#include "comedidev.h"
44#include <linux/cdev.h>
883db3d9 45#include <linux/stat.h>
ed9eccbe 46
476b8477
GKH
47#include <linux/io.h>
48#include <linux/uaccess.h>
ed9eccbe 49
3a5fa275 50#include "comedi_internal.h"
ed9eccbe
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);
1611 struct comedi_device_file_info *dev_file_info =
1612 comedi_get_device_file_info(minor);
1613 struct comedi_device *dev;
1614 int rc;
1615
1616 if (dev_file_info == NULL || dev_file_info->device == NULL)
1617 return -ENODEV;
1618 dev = dev_file_info->device;
1619
1620 mutex_lock(&dev->mutex);
1621
1622 /* Device config is special, because it must work on
1623 * an unconfigured device. */
1624 if (cmd == COMEDI_DEVCONFIG) {
1625 rc = do_devconfig_ioctl(dev,
1626 (struct comedi_devconfig __user *)arg);
1627 goto done;
1628 }
1629
1630 if (!dev->attached) {
1631 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
1632 rc = -ENODEV;
1633 goto done;
1634 }
1635
1636 switch (cmd) {
1637 case COMEDI_BUFCONFIG:
1638 rc = do_bufconfig_ioctl(dev,
1639 (struct comedi_bufconfig __user *)arg);
1640 break;
1641 case COMEDI_DEVINFO:
1642 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
1643 file);
1644 break;
1645 case COMEDI_SUBDINFO:
1646 rc = do_subdinfo_ioctl(dev,
1647 (struct comedi_subdinfo __user *)arg,
1648 file);
1649 break;
1650 case COMEDI_CHANINFO:
1651 rc = do_chaninfo_ioctl(dev, (void __user *)arg);
1652 break;
1653 case COMEDI_RANGEINFO:
1654 rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
1655 break;
1656 case COMEDI_BUFINFO:
1657 rc = do_bufinfo_ioctl(dev,
1658 (struct comedi_bufinfo __user *)arg,
1659 file);
1660 break;
1661 case COMEDI_LOCK:
1662 rc = do_lock_ioctl(dev, arg, file);
1663 break;
1664 case COMEDI_UNLOCK:
1665 rc = do_unlock_ioctl(dev, arg, file);
1666 break;
1667 case COMEDI_CANCEL:
1668 rc = do_cancel_ioctl(dev, arg, file);
1669 break;
1670 case COMEDI_CMD:
1671 rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
1672 break;
1673 case COMEDI_CMDTEST:
1674 rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
1675 file);
1676 break;
1677 case COMEDI_INSNLIST:
1678 rc = do_insnlist_ioctl(dev,
1679 (struct comedi_insnlist __user *)arg,
1680 file);
1681 break;
1682 case COMEDI_INSN:
1683 rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
1684 file);
1685 break;
1686 case COMEDI_POLL:
1687 rc = do_poll_ioctl(dev, arg, file);
1688 break;
1689 default:
1690 rc = -ENOTTY;
1691 break;
1692 }
1693
1694done:
1695 mutex_unlock(&dev->mutex);
1696 return rc;
1697}
1698
df30b21c
FV
1699static void comedi_vm_open(struct vm_area_struct *area)
1700{
1701 struct comedi_async *async;
1702 struct comedi_device *dev;
1703
1704 async = area->vm_private_data;
1705 dev = async->subdevice->device;
1706
1707 mutex_lock(&dev->mutex);
1708 async->mmap_count++;
1709 mutex_unlock(&dev->mutex);
1710}
1711
1712static void comedi_vm_close(struct vm_area_struct *area)
ed9eccbe 1713{
d163679c 1714 struct comedi_async *async;
71b5f4f1 1715 struct comedi_device *dev;
ed9eccbe
DS
1716
1717 async = area->vm_private_data;
1718 dev = async->subdevice->device;
1719
1720 mutex_lock(&dev->mutex);
1721 async->mmap_count--;
1722 mutex_unlock(&dev->mutex);
1723}
1724
1725static struct vm_operations_struct comedi_vm_ops = {
df30b21c
FV
1726 .open = comedi_vm_open,
1727 .close = comedi_vm_close,
ed9eccbe
DS
1728};
1729
1730static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1731{
1732 const unsigned minor = iminor(file->f_dentry->d_inode);
d163679c 1733 struct comedi_async *async = NULL;
ed9eccbe
DS
1734 unsigned long start = vma->vm_start;
1735 unsigned long size;
1736 int n_pages;
1737 int i;
1738 int retval;
34c43922 1739 struct comedi_subdevice *s;
3ffab428
BP
1740 struct comedi_device_file_info *dev_file_info;
1741 struct comedi_device *dev;
1742
1743 dev_file_info = comedi_get_device_file_info(minor);
1744 if (dev_file_info == NULL)
70fe742c 1745 return -ENODEV;
3ffab428
BP
1746 dev = dev_file_info->device;
1747 if (dev == NULL)
70fe742c 1748 return -ENODEV;
ed9eccbe
DS
1749
1750 mutex_lock(&dev->mutex);
1751 if (!dev->attached) {
1752 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1753 retval = -ENODEV;
1754 goto done;
1755 }
476b8477 1756 if (vma->vm_flags & VM_WRITE)
ed9eccbe 1757 s = comedi_get_write_subdevice(dev_file_info);
476b8477 1758 else
ed9eccbe 1759 s = comedi_get_read_subdevice(dev_file_info);
476b8477 1760
ed9eccbe
DS
1761 if (s == NULL) {
1762 retval = -EINVAL;
1763 goto done;
1764 }
1765 async = s->async;
1766 if (async == NULL) {
1767 retval = -EINVAL;
1768 goto done;
1769 }
1770
1771 if (vma->vm_pgoff != 0) {
1772 DPRINTK("comedi: mmap() offset must be 0.\n");
1773 retval = -EINVAL;
1774 goto done;
1775 }
1776
1777 size = vma->vm_end - vma->vm_start;
1778 if (size > async->prealloc_bufsz) {
1779 retval = -EFAULT;
1780 goto done;
1781 }
1782 if (size & (~PAGE_MASK)) {
1783 retval = -EFAULT;
1784 goto done;
1785 }
1786
1787 n_pages = size >> PAGE_SHIFT;
1788 for (i = 0; i < n_pages; ++i) {
1789 if (remap_pfn_range(vma, start,
0a85b6f0
MT
1790 page_to_pfn(virt_to_page
1791 (async->buf_page_list
1792 [i].virt_addr)), PAGE_SIZE,
1793 PAGE_SHARED)) {
ed9eccbe
DS
1794 retval = -EAGAIN;
1795 goto done;
1796 }
1797 start += PAGE_SIZE;
1798 }
1799
1800 vma->vm_ops = &comedi_vm_ops;
1801 vma->vm_private_data = async;
1802
1803 async->mmap_count++;
1804
1805 retval = 0;
476b8477 1806done:
ed9eccbe
DS
1807 mutex_unlock(&dev->mutex);
1808 return retval;
1809}
1810
1ae5062a 1811static unsigned int comedi_poll(struct file *file, poll_table *wait)
ed9eccbe
DS
1812{
1813 unsigned int mask = 0;
1814 const unsigned minor = iminor(file->f_dentry->d_inode);
34c43922
BP
1815 struct comedi_subdevice *read_subdev;
1816 struct comedi_subdevice *write_subdev;
3ffab428
BP
1817 struct comedi_device_file_info *dev_file_info;
1818 struct comedi_device *dev;
1819 dev_file_info = comedi_get_device_file_info(minor);
1820
1821 if (dev_file_info == NULL)
70fe742c 1822 return -ENODEV;
3ffab428
BP
1823 dev = dev_file_info->device;
1824 if (dev == NULL)
70fe742c 1825 return -ENODEV;
ed9eccbe
DS
1826
1827 mutex_lock(&dev->mutex);
1828 if (!dev->attached) {
1829 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1830 mutex_unlock(&dev->mutex);
1831 return 0;
1832 }
1833
1834 mask = 0;
1835 read_subdev = comedi_get_read_subdevice(dev_file_info);
1836 if (read_subdev) {
1837 poll_wait(file, &read_subdev->async->wait_head, wait);
1838 if (!read_subdev->busy
476b8477
GKH
1839 || comedi_buf_read_n_available(read_subdev->async) > 0
1840 || !(comedi_get_subdevice_runflags(read_subdev) &
1841 SRF_RUNNING)) {
ed9eccbe
DS
1842 mask |= POLLIN | POLLRDNORM;
1843 }
1844 }
1845 write_subdev = comedi_get_write_subdevice(dev_file_info);
1846 if (write_subdev) {
1847 poll_wait(file, &write_subdev->async->wait_head, wait);
476b8477
GKH
1848 comedi_buf_write_alloc(write_subdev->async,
1849 write_subdev->async->prealloc_bufsz);
ed9eccbe 1850 if (!write_subdev->busy
476b8477
GKH
1851 || !(comedi_get_subdevice_runflags(write_subdev) &
1852 SRF_RUNNING)
1853 || comedi_buf_write_n_allocated(write_subdev->async) >=
1854 bytes_per_sample(write_subdev->async->subdevice)) {
ed9eccbe
DS
1855 mask |= POLLOUT | POLLWRNORM;
1856 }
1857 }
1858
1859 mutex_unlock(&dev->mutex);
1860 return mask;
1861}
1862
92d0127c
GKH
1863static ssize_t comedi_write(struct file *file, const char __user *buf,
1864 size_t nbytes, loff_t *offset)
ed9eccbe 1865{
34c43922 1866 struct comedi_subdevice *s;
d163679c 1867 struct comedi_async *async;
ed9eccbe
DS
1868 int n, m, count = 0, retval = 0;
1869 DECLARE_WAITQUEUE(wait, current);
1870 const unsigned minor = iminor(file->f_dentry->d_inode);
3ffab428
BP
1871 struct comedi_device_file_info *dev_file_info;
1872 struct comedi_device *dev;
1873 dev_file_info = comedi_get_device_file_info(minor);
1874
1875 if (dev_file_info == NULL)
70fe742c 1876 return -ENODEV;
3ffab428
BP
1877 dev = dev_file_info->device;
1878 if (dev == NULL)
70fe742c 1879 return -ENODEV;
ed9eccbe
DS
1880
1881 if (!dev->attached) {
1882 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1883 retval = -ENODEV;
1884 goto done;
1885 }
1886
1887 s = comedi_get_write_subdevice(dev_file_info);
1888 if (s == NULL) {
1889 retval = -EIO;
1890 goto done;
1891 }
1892 async = s->async;
1893
1894 if (!nbytes) {
1895 retval = 0;
1896 goto done;
1897 }
1898 if (!s->busy) {
1899 retval = 0;
1900 goto done;
1901 }
1902 if (s->busy != file) {
1903 retval = -EACCES;
1904 goto done;
1905 }
1906 add_wait_queue(&async->wait_head, &wait);
1907 while (nbytes > 0 && !retval) {
1908 set_current_state(TASK_INTERRUPTIBLE);
1909
d2611540
IA
1910 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1911 if (count == 0) {
1912 if (comedi_get_subdevice_runflags(s) &
1913 SRF_ERROR) {
1914 retval = -EPIPE;
1915 } else {
1916 retval = 0;
1917 }
1918 do_become_nonbusy(dev, s);
1919 }
1920 break;
1921 }
1922
ed9eccbe
DS
1923 n = nbytes;
1924
1925 m = n;
476b8477 1926 if (async->buf_write_ptr + m > async->prealloc_bufsz)
ed9eccbe 1927 m = async->prealloc_bufsz - async->buf_write_ptr;
ed9eccbe 1928 comedi_buf_write_alloc(async, async->prealloc_bufsz);
476b8477 1929 if (m > comedi_buf_write_n_allocated(async))
ed9eccbe 1930 m = comedi_buf_write_n_allocated(async);
ed9eccbe
DS
1931 if (m < n)
1932 n = m;
1933
1934 if (n == 0) {
ed9eccbe
DS
1935 if (file->f_flags & O_NONBLOCK) {
1936 retval = -EAGAIN;
1937 break;
1938 }
6a9ce6b6 1939 schedule();
ed9eccbe
DS
1940 if (signal_pending(current)) {
1941 retval = -ERESTARTSYS;
1942 break;
1943 }
476b8477 1944 if (!s->busy)
ed9eccbe 1945 break;
ed9eccbe
DS
1946 if (s->busy != file) {
1947 retval = -EACCES;
1948 break;
1949 }
1950 continue;
1951 }
1952
1953 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
476b8477 1954 buf, n);
ed9eccbe
DS
1955 if (m) {
1956 n -= m;
1957 retval = -EFAULT;
1958 }
1959 comedi_buf_write_free(async, n);
1960
1961 count += n;
1962 nbytes -= n;
1963
1964 buf += n;
1965 break; /* makes device work like a pipe */
1966 }
1967 set_current_state(TASK_RUNNING);
1968 remove_wait_queue(&async->wait_head, &wait);
1969
1970done:
476b8477 1971 return count ? count : retval;
ed9eccbe
DS
1972}
1973
92d0127c 1974static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
6705b68d 1975 loff_t *offset)
ed9eccbe 1976{
34c43922 1977 struct comedi_subdevice *s;
d163679c 1978 struct comedi_async *async;
ed9eccbe
DS
1979 int n, m, count = 0, retval = 0;
1980 DECLARE_WAITQUEUE(wait, current);
1981 const unsigned minor = iminor(file->f_dentry->d_inode);
3ffab428
BP
1982 struct comedi_device_file_info *dev_file_info;
1983 struct comedi_device *dev;
1984 dev_file_info = comedi_get_device_file_info(minor);
1985
1986 if (dev_file_info == NULL)
70fe742c 1987 return -ENODEV;
3ffab428
BP
1988 dev = dev_file_info->device;
1989 if (dev == NULL)
70fe742c 1990 return -ENODEV;
ed9eccbe
DS
1991
1992 if (!dev->attached) {
1993 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1994 retval = -ENODEV;
1995 goto done;
1996 }
1997
1998 s = comedi_get_read_subdevice(dev_file_info);
1999 if (s == NULL) {
2000 retval = -EIO;
2001 goto done;
2002 }
2003 async = s->async;
2004 if (!nbytes) {
2005 retval = 0;
2006 goto done;
2007 }
2008 if (!s->busy) {
2009 retval = 0;
2010 goto done;
2011 }
2012 if (s->busy != file) {
2013 retval = -EACCES;
2014 goto done;
2015 }
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) {
2032 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
2033 do_become_nonbusy(dev, s);
2034 if (comedi_get_subdevice_runflags(s) &
476b8477 2035 SRF_ERROR) {
ed9eccbe
DS
2036 retval = -EPIPE;
2037 } else {
2038 retval = 0;
2039 }
2040 break;
2041 }
2042 if (file->f_flags & O_NONBLOCK) {
2043 retval = -EAGAIN;
2044 break;
2045 }
6a9ce6b6 2046 schedule();
ed9eccbe
DS
2047 if (signal_pending(current)) {
2048 retval = -ERESTARTSYS;
2049 break;
2050 }
ed9eccbe
DS
2051 if (!s->busy) {
2052 retval = 0;
2053 break;
2054 }
2055 if (s->busy != file) {
2056 retval = -EACCES;
2057 break;
2058 }
2059 continue;
2060 }
2061 m = copy_to_user(buf, async->prealloc_buf +
476b8477 2062 async->buf_read_ptr, n);
ed9eccbe
DS
2063 if (m) {
2064 n -= m;
2065 retval = -EFAULT;
2066 }
2067
2068 comedi_buf_read_alloc(async, n);
2069 comedi_buf_read_free(async, n);
2070
2071 count += n;
2072 nbytes -= n;
2073
2074 buf += n;
2075 break; /* makes device work like a pipe */
2076 }
2077 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
476b8477 2078 async->buf_read_count - async->buf_write_count == 0) {
ed9eccbe
DS
2079 do_become_nonbusy(dev, s);
2080 }
2081 set_current_state(TASK_RUNNING);
2082 remove_wait_queue(&async->wait_head, &wait);
2083
2084done:
476b8477 2085 return count ? count : retval;
ed9eccbe
DS
2086}
2087
ed9eccbe
DS
2088static int comedi_open(struct inode *inode, struct file *file)
2089{
ed9eccbe 2090 const unsigned minor = iminor(inode);
476b8477
GKH
2091 struct comedi_device_file_info *dev_file_info =
2092 comedi_get_device_file_info(minor);
0a85b6f0
MT
2093 struct comedi_device *dev =
2094 dev_file_info ? dev_file_info->device : NULL;
97920071 2095
ed9eccbe
DS
2096 if (dev == NULL) {
2097 DPRINTK("invalid minor number\n");
2098 return -ENODEV;
2099 }
2100
2101 /* This is slightly hacky, but we want module autoloading
2102 * to work for root.
2103 * case: user opens device, attached -> ok
2104 * case: user opens device, unattached, in_request_module=0 -> autoload
2105 * case: user opens device, unattached, in_request_module=1 -> fail
2106 * case: root opens device, attached -> ok
2107 * case: root opens device, unattached, in_request_module=1 -> ok
2108 * (typically called from modprobe)
2109 * case: root opens device, unattached, in_request_module=0 -> autoload
2110 *
2111 * The last could be changed to "-> ok", which would deny root
2112 * autoloading.
2113 */
2114 mutex_lock(&dev->mutex);
2115 if (dev->attached)
2116 goto ok;
a8f80e8f 2117 if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
ed9eccbe
DS
2118 DPRINTK("in request module\n");
2119 mutex_unlock(&dev->mutex);
2120 return -ENODEV;
2121 }
a8f80e8f 2122 if (capable(CAP_NET_ADMIN) && dev->in_request_module)
ed9eccbe
DS
2123 goto ok;
2124
2125 dev->in_request_module = 1;
2126
ed9eccbe
DS
2127#ifdef CONFIG_KMOD
2128 mutex_unlock(&dev->mutex);
56d92c60 2129 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
ed9eccbe
DS
2130 mutex_lock(&dev->mutex);
2131#endif
2132
2133 dev->in_request_module = 0;
2134
a8f80e8f
EP
2135 if (!dev->attached && !capable(CAP_NET_ADMIN)) {
2136 DPRINTK("not attached and not CAP_NET_ADMIN\n");
ed9eccbe
DS
2137 mutex_unlock(&dev->mutex);
2138 return -ENODEV;
2139 }
2140ok:
2141 __module_get(THIS_MODULE);
2142
2143 if (dev->attached) {
2144 if (!try_module_get(dev->driver->module)) {
2145 module_put(THIS_MODULE);
2146 mutex_unlock(&dev->mutex);
2147 return -ENOSYS;
2148 }
2149 }
2150
3c17ba07
IA
2151 if (dev->attached && dev->use_count == 0 && dev->open) {
2152 int rc = dev->open(dev);
2153 if (rc < 0) {
2154 module_put(dev->driver->module);
2155 module_put(THIS_MODULE);
2156 mutex_unlock(&dev->mutex);
2157 return rc;
2158 }
2159 }
ed9eccbe
DS
2160
2161 dev->use_count++;
2162
a5011a26 2163 mutex_unlock(&dev->mutex);
ed9eccbe 2164
a5011a26 2165 return 0;
ed9eccbe
DS
2166}
2167
2aae0076
HS
2168static int comedi_fasync(int fd, struct file *file, int on)
2169{
2170 const unsigned minor = iminor(file->f_dentry->d_inode);
2171 struct comedi_device_file_info *dev_file_info;
2172 struct comedi_device *dev;
2173 dev_file_info = comedi_get_device_file_info(minor);
2174
2175 if (dev_file_info == NULL)
2176 return -ENODEV;
2177 dev = dev_file_info->device;
2178 if (dev == NULL)
2179 return -ENODEV;
2180
2181 return fasync_helper(fd, file, on, &dev->async_queue);
2182}
2183
a5011a26 2184static int comedi_close(struct inode *inode, struct file *file)
ed9eccbe 2185{
a5011a26
HS
2186 const unsigned minor = iminor(inode);
2187 struct comedi_subdevice *s = NULL;
ed9eccbe 2188 int i;
a5011a26
HS
2189 struct comedi_device_file_info *dev_file_info;
2190 struct comedi_device *dev;
2191 dev_file_info = comedi_get_device_file_info(minor);
ed9eccbe 2192
a5011a26
HS
2193 if (dev_file_info == NULL)
2194 return -ENODEV;
2195 dev = dev_file_info->device;
2196 if (dev == NULL)
2197 return -ENODEV;
ed9eccbe 2198
a5011a26
HS
2199 mutex_lock(&dev->mutex);
2200
2201 if (dev->subdevices) {
2202 for (i = 0; i < dev->n_subdevices; i++) {
b077f2cd 2203 s = &dev->subdevices[i];
a5011a26
HS
2204
2205 if (s->busy == file)
2206 do_cancel(dev, s);
2207 if (s->lock == file)
2208 s->lock = NULL;
2209 }
ed9eccbe 2210 }
a5011a26
HS
2211 if (dev->attached && dev->use_count == 1 && dev->close)
2212 dev->close(dev);
2213
2214 module_put(THIS_MODULE);
2215 if (dev->attached)
2216 module_put(dev->driver->module);
2217
2218 dev->use_count--;
2219
2220 mutex_unlock(&dev->mutex);
2221
2222 if (file->f_flags & FASYNC)
2223 comedi_fasync(-1, file, 0);
ed9eccbe
DS
2224
2225 return 0;
2226}
2227
8cb8aad7 2228static const struct file_operations comedi_fops = {
a5011a26
HS
2229 .owner = THIS_MODULE,
2230 .unlocked_ioctl = comedi_unlocked_ioctl,
2231 .compat_ioctl = comedi_compat_ioctl,
2232 .open = comedi_open,
2233 .release = comedi_close,
2234 .read = comedi_read,
2235 .write = comedi_write,
2236 .mmap = comedi_mmap,
2237 .poll = comedi_poll,
2238 .fasync = comedi_fasync,
2239 .llseek = noop_llseek,
2240};
2241
8cb8aad7 2242static struct class *comedi_class;
a5011a26
HS
2243static struct cdev comedi_cdev;
2244
2245static void comedi_cleanup_legacy_minors(void)
ed9eccbe 2246{
ed9eccbe
DS
2247 unsigned i;
2248
a5011a26 2249 for (i = 0; i < comedi_num_legacy_minors; i++)
883db3d9 2250 comedi_free_board_minor(i);
ed9eccbe
DS
2251}
2252
a5011a26 2253static int __init comedi_init(void)
ed9eccbe 2254{
a5011a26
HS
2255 int i;
2256 int retval;
ed9eccbe 2257
4f870fe6 2258 pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
ed9eccbe 2259
a5011a26
HS
2260 if (comedi_num_legacy_minors < 0 ||
2261 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
4f870fe6
IA
2262 pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n",
2263 COMEDI_NUM_BOARD_MINORS);
a5011a26 2264 return -EINVAL;
ed9eccbe 2265 }
c43435d7 2266
a5011a26
HS
2267 /*
2268 * comedi is unusable if both comedi_autoconfig and
2269 * comedi_num_legacy_minors are zero, so we might as well adjust the
2270 * defaults in that case
2271 */
2272 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
2273 comedi_num_legacy_minors = 16;
c43435d7 2274
a5011a26
HS
2275 memset(comedi_file_info_table, 0,
2276 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
ed9eccbe 2277
a5011a26
HS
2278 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2279 COMEDI_NUM_MINORS, "comedi");
2280 if (retval)
2281 return -EIO;
2282 cdev_init(&comedi_cdev, &comedi_fops);
2283 comedi_cdev.owner = THIS_MODULE;
2284 kobject_set_name(&comedi_cdev.kobj, "comedi");
2285 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2286 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2287 COMEDI_NUM_MINORS);
2288 return -EIO;
883db3d9 2289 }
a5011a26
HS
2290 comedi_class = class_create(THIS_MODULE, "comedi");
2291 if (IS_ERR(comedi_class)) {
4f870fe6 2292 pr_err("comedi: failed to create class\n");
a5011a26
HS
2293 cdev_del(&comedi_cdev);
2294 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2295 COMEDI_NUM_MINORS);
2296 return PTR_ERR(comedi_class);
883db3d9 2297 }
a5011a26 2298
fb60367d
HS
2299 comedi_class->dev_attrs = comedi_dev_attrs;
2300
a5011a26
HS
2301 /* XXX requires /proc interface */
2302 comedi_proc_init();
2303
2304 /* create devices files for legacy/manual use */
2305 for (i = 0; i < comedi_num_legacy_minors; i++) {
2306 int minor;
2307 minor = comedi_alloc_board_minor(NULL);
2308 if (minor < 0) {
2309 comedi_cleanup_legacy_minors();
2310 cdev_del(&comedi_cdev);
2311 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2312 COMEDI_NUM_MINORS);
2313 return minor;
2314 }
883db3d9 2315 }
a5011a26
HS
2316
2317 return 0;
ed9eccbe
DS
2318}
2319
a5011a26 2320static void __exit comedi_cleanup(void)
ed9eccbe 2321{
a5011a26 2322 int i;
ed9eccbe 2323
a5011a26
HS
2324 comedi_cleanup_legacy_minors();
2325 for (i = 0; i < COMEDI_NUM_MINORS; ++i)
2326 BUG_ON(comedi_file_info_table[i]);
ed9eccbe 2327
a5011a26
HS
2328 class_destroy(comedi_class);
2329 cdev_del(&comedi_cdev);
2330 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
ed9eccbe 2331
a5011a26 2332 comedi_proc_cleanup();
ed9eccbe
DS
2333}
2334
a5011a26
HS
2335module_init(comedi_init);
2336module_exit(comedi_cleanup);
ed9eccbe 2337
a5011a26
HS
2338void comedi_error(const struct comedi_device *dev, const char *s)
2339{
4f870fe6 2340 dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
ed9eccbe 2341}
a5011a26 2342EXPORT_SYMBOL(comedi_error);
883db3d9 2343
a5011a26 2344void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
883db3d9 2345{
a5011a26
HS
2346 struct comedi_async *async = s->async;
2347 unsigned runflags = 0;
2348 unsigned runflags_mask = 0;
883db3d9 2349
a5011a26 2350 /* DPRINTK("comedi_event 0x%x\n",mask); */
883db3d9 2351
a5011a26
HS
2352 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2353 return;
2354
2355 if (s->
2356 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2357 COMEDI_CB_OVERFLOW)) {
2358 runflags_mask |= SRF_RUNNING;
883db3d9 2359 }
a5011a26
HS
2360 /* remember if an error event has occurred, so an error
2361 * can be returned the next time the user does a read() */
2362 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2363 runflags_mask |= SRF_ERROR;
2364 runflags |= SRF_ERROR;
883db3d9 2365 }
a5011a26
HS
2366 if (runflags_mask) {
2367 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2368 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
883db3d9
FMH
2369 }
2370
a5011a26
HS
2371 if (async->cb_mask & s->async->events) {
2372 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2373 wake_up_interruptible(&async->wait_head);
2374 if (s->subdev_flags & SDF_CMD_READ)
2375 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2376 if (s->subdev_flags & SDF_CMD_WRITE)
2377 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2378 } else {
2379 if (async->cb_func)
2380 async->cb_func(s->async->events, async->cb_arg);
2381 }
2382 }
2383 s->async->events = 0;
883db3d9 2384}
a5011a26 2385EXPORT_SYMBOL(comedi_event);
883db3d9 2386
a5011a26 2387unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
883db3d9 2388{
a5011a26
HS
2389 unsigned long flags;
2390 unsigned runflags;
883db3d9 2391
a5011a26
HS
2392 spin_lock_irqsave(&s->spin_lock, flags);
2393 runflags = s->runflags;
2394 spin_unlock_irqrestore(&s->spin_lock, flags);
2395 return runflags;
883db3d9 2396}
a5011a26 2397EXPORT_SYMBOL(comedi_get_subdevice_runflags);
883db3d9 2398
a5011a26
HS
2399static void comedi_device_init(struct comedi_device *dev)
2400{
2401 memset(dev, 0, sizeof(struct comedi_device));
2402 spin_lock_init(&dev->spinlock);
2403 mutex_init(&dev->mutex);
2404 dev->minor = -1;
2405}
883db3d9 2406
a5011a26 2407static void comedi_device_cleanup(struct comedi_device *dev)
883db3d9 2408{
a5011a26
HS
2409 if (dev == NULL)
2410 return;
2411 mutex_lock(&dev->mutex);
2412 comedi_device_detach(dev);
2413 mutex_unlock(&dev->mutex);
2414 mutex_destroy(&dev->mutex);
2415}
2416
2417int comedi_alloc_board_minor(struct device *hardware_device)
2418{
2419 struct comedi_device_file_info *info;
2420 struct device *csdev;
2421 unsigned i;
a5011a26
HS
2422
2423 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2424 if (info == NULL)
2425 return -ENOMEM;
2426 info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2427 if (info->device == NULL) {
2428 kfree(info);
2429 return -ENOMEM;
2430 }
2431 info->hardware_device = hardware_device;
2432 comedi_device_init(info->device);
2433 spin_lock(&comedi_file_info_table_lock);
2434 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2435 if (comedi_file_info_table[i] == NULL) {
2436 comedi_file_info_table[i] = info;
2437 break;
2438 }
2439 }
2440 spin_unlock(&comedi_file_info_table_lock);
2441 if (i == COMEDI_NUM_BOARD_MINORS) {
2442 comedi_device_cleanup(info->device);
2443 kfree(info->device);
2444 kfree(info);
4f870fe6 2445 pr_err("comedi: error: ran out of minor numbers for board device files.\n");
a5011a26
HS
2446 return -EBUSY;
2447 }
2448 info->device->minor = i;
2449 csdev = device_create(comedi_class, hardware_device,
2450 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2451 if (!IS_ERR(csdev))
2452 info->device->class_dev = csdev;
2453 dev_set_drvdata(csdev, info);
883db3d9 2454
a5011a26 2455 return i;
883db3d9
FMH
2456}
2457
a5011a26 2458void comedi_free_board_minor(unsigned minor)
883db3d9 2459{
a5011a26 2460 struct comedi_device_file_info *info;
883db3d9 2461
a5011a26
HS
2462 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2463 spin_lock(&comedi_file_info_table_lock);
2464 info = comedi_file_info_table[minor];
2465 comedi_file_info_table[minor] = NULL;
2466 spin_unlock(&comedi_file_info_table_lock);
883db3d9 2467
a5011a26
HS
2468 if (info) {
2469 struct comedi_device *dev = info->device;
2470 if (dev) {
2471 if (dev->class_dev) {
2472 device_destroy(comedi_class,
2473 MKDEV(COMEDI_MAJOR, dev->minor));
2474 }
2475 comedi_device_cleanup(dev);
2476 kfree(dev);
2477 }
2478 kfree(info);
883db3d9 2479 }
883db3d9
FMH
2480}
2481
a5011a26 2482int comedi_find_board_minor(struct device *hardware_device)
883db3d9 2483{
a5011a26
HS
2484 int minor;
2485 struct comedi_device_file_info *info;
883db3d9 2486
a5011a26
HS
2487 for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
2488 spin_lock(&comedi_file_info_table_lock);
2489 info = comedi_file_info_table[minor];
2490 if (info && info->hardware_device == hardware_device) {
2491 spin_unlock(&comedi_file_info_table_lock);
2492 return minor;
2493 }
2494 spin_unlock(&comedi_file_info_table_lock);
883db3d9 2495 }
a5011a26 2496 return -ENODEV;
883db3d9
FMH
2497}
2498
a5011a26
HS
2499int comedi_alloc_subdevice_minor(struct comedi_device *dev,
2500 struct comedi_subdevice *s)
883db3d9 2501{
a5011a26
HS
2502 struct comedi_device_file_info *info;
2503 struct device *csdev;
2504 unsigned i;
883db3d9 2505
a5011a26
HS
2506 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2507 if (info == NULL)
2508 return -ENOMEM;
2509 info->device = dev;
2510 info->read_subdevice = s;
2511 info->write_subdevice = s;
2512 spin_lock(&comedi_file_info_table_lock);
2513 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2514 if (comedi_file_info_table[i] == NULL) {
2515 comedi_file_info_table[i] = info;
2516 break;
2517 }
2518 }
2519 spin_unlock(&comedi_file_info_table_lock);
2520 if (i == COMEDI_NUM_MINORS) {
2521 kfree(info);
4f870fe6 2522 pr_err("comedi: error: ran out of minor numbers for board device files.\n");
a5011a26
HS
2523 return -EBUSY;
2524 }
2525 s->minor = i;
2526 csdev = device_create(comedi_class, dev->class_dev,
2527 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
2528 dev->minor, (int)(s - dev->subdevices));
2529 if (!IS_ERR(csdev))
2530 s->class_dev = csdev;
2531 dev_set_drvdata(csdev, info);
883db3d9 2532
a5011a26 2533 return i;
883db3d9
FMH
2534}
2535
a5011a26 2536void comedi_free_subdevice_minor(struct comedi_subdevice *s)
883db3d9 2537{
a5011a26 2538 struct comedi_device_file_info *info;
883db3d9 2539
a5011a26
HS
2540 if (s == NULL)
2541 return;
2542 if (s->minor < 0)
2543 return;
883db3d9 2544
a5011a26
HS
2545 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2546 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
883db3d9 2547
a5011a26
HS
2548 spin_lock(&comedi_file_info_table_lock);
2549 info = comedi_file_info_table[s->minor];
2550 comedi_file_info_table[s->minor] = NULL;
2551 spin_unlock(&comedi_file_info_table_lock);
883db3d9 2552
a5011a26
HS
2553 if (s->class_dev) {
2554 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2555 s->class_dev = NULL;
883db3d9 2556 }
a5011a26 2557 kfree(info);
883db3d9
FMH
2558}
2559
a5011a26
HS
2560struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2561{
2562 struct comedi_device_file_info *info;
2563
2564 BUG_ON(minor >= COMEDI_NUM_MINORS);
2565 spin_lock(&comedi_file_info_table_lock);
2566 info = comedi_file_info_table[minor];
2567 spin_unlock(&comedi_file_info_table_lock);
2568 return info;
2569}
2570EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
This page took 0.677063 seconds and 5 git commands to generate.