Root/drivers/staging/comedi/comedi_fops.c

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

Archive Download this file



interactive