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