5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
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.
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.
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.
26 #define __NO_VERSION__
27 #include "comedi_fops.h"
28 #include "comedi_compat32.h"
30 #include <linux/module.h>
31 #include <linux/errno.h>
32 #include <linux/kernel.h>
33 #include <linux/sched.h>
34 #include <linux/fcntl.h>
35 #include <linux/delay.h>
36 #include <linux/ioport.h>
38 #include <linux/slab.h>
39 #include <linux/kmod.h>
40 #include <linux/poll.h>
41 #include <linux/init.h>
42 #include <linux/device.h>
43 #include <linux/vmalloc.h>
45 #include "comedidev.h"
46 #include <linux/cdev.h>
49 #include <linux/uaccess.h>
51 /* #include "kvmem.h" */
53 MODULE_AUTHOR("http://www.comedi.org");
54 MODULE_DESCRIPTION("Comedi core module");
55 MODULE_LICENSE("GPL");
57 #ifdef CONFIG_COMEDI_DEBUG
59 module_param(comedi_debug, int, 0644);
62 int comedi_autoconfig = 1;
63 module_param(comedi_autoconfig, bool, 0444);
65 int comedi_num_legacy_minors = 0;
66 module_param(comedi_num_legacy_minors, int, 0444);
68 static DEFINE_SPINLOCK(comedi_file_info_table_lock);
69 static struct comedi_device_file_info
70 *comedi_file_info_table[COMEDI_NUM_MINORS];
72 static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg);
73 static int do_bufconfig_ioctl(comedi_device *dev, void *arg);
74 static int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
76 static int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
78 static int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg);
79 static int do_bufinfo_ioctl(comedi_device *dev, void *arg);
80 static int do_cmd_ioctl(comedi_device *dev, void *arg, void *file);
81 static int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file);
82 static int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file);
83 static int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file);
84 static int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file);
85 static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file);
86 static int do_insn_ioctl(comedi_device *dev, void *arg, void *file);
87 static int do_poll_ioctl(comedi_device *dev, unsigned int subd, void *file);
89 extern void do_become_nonbusy(comedi_device *dev, comedi_subdevice *s);
90 static int do_cancel(comedi_device *dev, comedi_subdevice *s);
92 static int comedi_fasync(int fd, struct file *file, int on);
94 static int is_device_busy(comedi_device *dev);
96 #ifdef HAVE_UNLOCKED_IOCTL
97 static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
100 static int comedi_ioctl(struct inode *inode, struct file *file,
101 unsigned int cmd, unsigned long arg)
104 const unsigned minor = iminor(file->f_dentry->d_inode);
105 struct comedi_device_file_info *dev_file_info =
106 comedi_get_device_file_info(minor);
110 if (dev_file_info == NULL || dev_file_info->device == NULL)
112 dev = dev_file_info->device;
114 mutex_lock(&dev->mutex);
116 /* Device config is special, because it must work on
117 * an unconfigured device. */
118 if (cmd == COMEDI_DEVCONFIG) {
119 rc = do_devconfig_ioctl(dev, (void *)arg);
123 if (!dev->attached) {
124 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
130 case COMEDI_BUFCONFIG:
131 rc = do_bufconfig_ioctl(dev, (void *)arg);
134 rc = do_devinfo_ioctl(dev, (void *)arg, file);
136 case COMEDI_SUBDINFO:
137 rc = do_subdinfo_ioctl(dev, (void *)arg, file);
139 case COMEDI_CHANINFO:
140 rc = do_chaninfo_ioctl(dev, (void *)arg);
142 case COMEDI_RANGEINFO:
143 rc = do_rangeinfo_ioctl(dev, (void *)arg);
146 rc = do_bufinfo_ioctl(dev, (void *)arg);
149 rc = do_lock_ioctl(dev, arg, file);
152 rc = do_unlock_ioctl(dev, arg, file);
155 rc = do_cancel_ioctl(dev, arg, file);
158 rc = do_cmd_ioctl(dev, (void *)arg, file);
161 rc = do_cmdtest_ioctl(dev, (void *)arg, file);
163 case COMEDI_INSNLIST:
164 rc = do_insnlist_ioctl(dev, (void *)arg, file);
167 rc = do_insn_ioctl(dev, (void *)arg, file);
170 rc = do_poll_ioctl(dev, arg, file);
178 mutex_unlock(&dev->mutex);
187 pointer to devconfig structure
190 devconfig structure at arg
195 static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg)
199 unsigned char *aux_data = NULL;
202 if (!capable(CAP_SYS_ADMIN))
206 if (is_device_busy(dev))
209 struct module *driver_module = dev->driver->module;
210 comedi_device_detach(dev);
211 module_put(driver_module);
216 if (copy_from_user(&it, arg, sizeof(comedi_devconfig)))
219 it.board_name[COMEDI_NAMELEN - 1] = 0;
221 if (comedi_aux_data(it.options, 0) &&
222 it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
224 aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
228 aux_data = vmalloc(aux_len);
232 if (copy_from_user(aux_data,
233 comedi_aux_data(it.options, 0), aux_len)) {
237 it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
238 (unsigned long)aux_data;
239 if (sizeof(void *) > sizeof(int)) {
240 bit_shift = sizeof(int) * 8;
241 it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
242 ((unsigned long)aux_data) >> bit_shift;
244 it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
247 ret = comedi_device_attach(dev, &it);
249 if (!try_module_get(dev->driver->module)) {
250 comedi_device_detach(dev);
263 buffer configuration ioctl
266 pointer to bufconfig structure
272 modified bufconfig at arg
275 static int do_bufconfig_ioctl(comedi_device *dev, void *arg)
282 if (copy_from_user(&bc, arg, sizeof(comedi_bufconfig)))
285 if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
288 s = dev->subdevices + bc.subdevice;
292 DPRINTK("subdevice does not have async capability\n");
298 if (bc.maximum_size) {
299 if (!capable(CAP_SYS_ADMIN))
302 async->max_bufsize = bc.maximum_size;
306 if (bc.size > async->max_bufsize)
310 DPRINTK("subdevice is busy, cannot resize buffer\n");
313 if (async->mmap_count) {
314 DPRINTK("subdevice is mmapped, cannot resize buffer\n");
318 if (!async->prealloc_buf)
321 /* make sure buffer is an integral number of pages
323 bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK;
325 ret = comedi_buf_alloc(dev, s, bc.size);
330 ret = s->buf_change(dev, s, bc.size);
335 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
336 dev->minor, bc.subdevice, async->prealloc_bufsz);
339 bc.size = async->prealloc_bufsz;
340 bc.maximum_size = async->max_bufsize;
343 if (copy_to_user(arg, &bc, sizeof(comedi_bufconfig)))
354 pointer to devinfo structure
363 static int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
366 comedi_devinfo devinfo;
367 const unsigned minor = iminor(file->f_dentry->d_inode);
368 struct comedi_device_file_info *dev_file_info =
369 comedi_get_device_file_info(minor);
370 comedi_subdevice *read_subdev =
371 comedi_get_read_subdevice(dev_file_info);
372 comedi_subdevice *write_subdev =
373 comedi_get_write_subdevice(dev_file_info);
375 memset(&devinfo, 0, sizeof(devinfo));
377 /* fill devinfo structure */
378 devinfo.version_code = COMEDI_VERSION_CODE;
379 devinfo.n_subdevs = dev->n_subdevices;
380 memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
381 memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
384 devinfo.read_subdevice = read_subdev - dev->subdevices;
386 devinfo.read_subdevice = -1;
389 devinfo.write_subdevice = write_subdev - dev->subdevices;
391 devinfo.write_subdevice = -1;
393 if (copy_to_user(arg, &devinfo, sizeof(comedi_devinfo)))
404 pointer to array of subdevice info structures
410 array of subdevice info structures at arg
413 static int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
417 comedi_subdinfo *tmp, *us;
420 tmp = kcalloc(dev->n_subdevices, sizeof(comedi_subdinfo), GFP_KERNEL);
424 /* fill subdinfo structs */
425 for (i = 0; i < dev->n_subdevices; i++) {
426 s = dev->subdevices + i;
430 us->n_chan = s->n_chan;
431 us->subd_flags = s->subdev_flags;
432 if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
433 us->subd_flags |= SDF_RUNNING;
434 #define TIMER_nanosec 5 /* backwards compatibility */
435 us->timer_type = TIMER_nanosec;
436 us->len_chanlist = s->len_chanlist;
437 us->maxdata = s->maxdata;
438 if (s->range_table) {
440 (i << 24) | (0 << 16) | (s->range_table->length);
442 us->range_type = 0; /* XXX */
444 us->flags = s->flags;
447 us->subd_flags |= SDF_BUSY;
449 us->subd_flags |= SDF_BUSY_OWNER;
451 us->subd_flags |= SDF_LOCKED;
453 us->subd_flags |= SDF_LOCK_OWNER;
454 if (!s->maxdata && s->maxdata_list)
455 us->subd_flags |= SDF_MAXDATA;
457 us->subd_flags |= SDF_FLAGS;
458 if (s->range_table_list)
459 us->subd_flags |= SDF_RANGETYPE;
461 us->subd_flags |= SDF_CMD;
463 if (s->insn_bits != &insn_inval)
464 us->insn_bits_support = COMEDI_SUPPORTED;
466 us->insn_bits_support = COMEDI_UNSUPPORTED;
468 us->settling_time_0 = s->settling_time_0;
471 ret = copy_to_user(arg, tmp,
472 dev->n_subdevices * sizeof(comedi_subdinfo));
476 return ret ? -EFAULT : 0;
484 pointer to chaninfo structure
487 chaninfo structure at arg
490 arrays at elements of chaninfo structure
493 static int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg)
498 if (copy_from_user(&it, arg, sizeof(comedi_chaninfo)))
501 if (it.subdev >= dev->n_subdevices)
503 s = dev->subdevices + it.subdev;
505 if (it.maxdata_list) {
506 if (s->maxdata || !s->maxdata_list)
508 if (copy_to_user(it.maxdata_list, s->maxdata_list,
509 s->n_chan * sizeof(unsigned int)))
516 if (copy_to_user(it.flaglist, s->flaglist,
517 s->n_chan * sizeof(unsigned int)))
524 if (!s->range_table_list)
526 for (i = 0; i < s->n_chan; i++) {
529 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
530 (s->range_table_list[i]->length);
531 put_user(x, it.rangelist + i);
534 if (copy_to_user(it.rangelist, s->range_type_list,
535 s->n_chan*sizeof(unsigned int)))
545 buffer information ioctl
548 pointer to bufinfo structure
554 modified bufinfo at arg
557 static int do_bufinfo_ioctl(comedi_device *dev, void *arg)
563 if (copy_from_user(&bi, arg, sizeof(comedi_bufinfo)))
566 if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
569 s = dev->subdevices + bi.subdevice;
573 DPRINTK("subdevice does not have async capability\n");
574 bi.buf_write_ptr = 0;
576 bi.buf_write_count = 0;
577 bi.buf_read_count = 0;
581 if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
582 bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
583 comedi_buf_read_free(async, bi.bytes_read);
585 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
587 && async->buf_write_count == async->buf_read_count) {
588 do_become_nonbusy(dev, s);
592 if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
594 comedi_buf_write_alloc(async, bi.bytes_written);
595 comedi_buf_write_free(async, bi.bytes_written);
598 bi.buf_write_count = async->buf_write_count;
599 bi.buf_write_ptr = async->buf_write_ptr;
600 bi.buf_read_count = async->buf_read_count;
601 bi.buf_read_ptr = async->buf_read_ptr;
604 if (copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
610 static int parse_insn(comedi_device *dev, comedi_insn *insn, unsigned int *data,
614 * synchronous instructions
617 * pointer to sync cmd structure
620 * sync cmd struct at arg
627 /* arbitrary limits */
628 #define MAX_SAMPLES 256
629 static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file)
631 comedi_insnlist insnlist;
632 comedi_insn *insns = NULL;
633 unsigned int *data = NULL;
637 if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist)))
640 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
642 DPRINTK("kmalloc failed\n");
647 insns = kmalloc(sizeof(comedi_insn) * insnlist.n_insns, GFP_KERNEL);
649 DPRINTK("kmalloc failed\n");
654 if (copy_from_user(insns, insnlist.insns,
655 sizeof(comedi_insn) * insnlist.n_insns)) {
656 DPRINTK("copy_from_user failed\n");
661 for (i = 0; i < insnlist.n_insns; i++) {
662 if (insns[i].n > MAX_SAMPLES) {
663 DPRINTK("number of samples too large\n");
667 if (insns[i].insn & INSN_MASK_WRITE) {
668 if (copy_from_user(data, insns[i].data,
669 insns[i].n * sizeof(unsigned int))) {
670 DPRINTK("copy_from_user failed\n");
675 ret = parse_insn(dev, insns + i, data, file);
678 if (insns[i].insn & INSN_MASK_READ) {
679 if (copy_to_user(insns[i].data, data,
680 insns[i].n * sizeof(unsigned int))) {
681 DPRINTK("copy_to_user failed\n");
699 static int check_insn_config_length(comedi_insn *insn, unsigned int *data)
705 case INSN_CONFIG_DIO_OUTPUT:
706 case INSN_CONFIG_DIO_INPUT:
707 case INSN_CONFIG_DISARM:
708 case INSN_CONFIG_RESET:
712 case INSN_CONFIG_ARM:
713 case INSN_CONFIG_DIO_QUERY:
714 case INSN_CONFIG_BLOCK_SIZE:
715 case INSN_CONFIG_FILTER:
716 case INSN_CONFIG_SERIAL_CLOCK:
717 case INSN_CONFIG_BIDIRECTIONAL_DATA:
718 case INSN_CONFIG_ALT_SOURCE:
719 case INSN_CONFIG_SET_COUNTER_MODE:
720 case INSN_CONFIG_8254_READ_STATUS:
721 case INSN_CONFIG_SET_ROUTING:
722 case INSN_CONFIG_GET_ROUTING:
723 case INSN_CONFIG_GET_PWM_STATUS:
724 case INSN_CONFIG_PWM_SET_PERIOD:
725 case INSN_CONFIG_PWM_GET_PERIOD:
729 case INSN_CONFIG_SET_GATE_SRC:
730 case INSN_CONFIG_GET_GATE_SRC:
731 case INSN_CONFIG_SET_CLOCK_SRC:
732 case INSN_CONFIG_GET_CLOCK_SRC:
733 case INSN_CONFIG_SET_OTHER_SRC:
734 case INSN_CONFIG_GET_COUNTER_STATUS:
735 case INSN_CONFIG_PWM_SET_H_BRIDGE:
736 case INSN_CONFIG_PWM_GET_H_BRIDGE:
737 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
741 case INSN_CONFIG_PWM_OUTPUT:
742 case INSN_CONFIG_ANALOG_TRIG:
746 /* by default we allow the insn since we don't have checks for
747 * all possible cases yet */
749 rt_printk("comedi: no check for data length of config insn id "
750 "%i is implemented.\n"
751 " Add a check to %s in %s.\n"
752 " Assuming n=%i is correct.\n", data[0], __func__,
760 static int parse_insn(comedi_device *dev, comedi_insn *insn, unsigned int *data,
767 if (insn->insn & INSN_MASK_SPECIAL) {
768 /* a non-subdevice instruction */
770 switch (insn->insn) {
780 do_gettimeofday(&tv);
782 data[1] = tv.tv_usec;
788 if (insn->n != 1 || data[0] >= 100000) {
792 udelay(data[0] / 1000);
800 if (insn->subdev >= dev->n_subdevices) {
801 DPRINTK("%d not usable subdevice\n",
806 s = dev->subdevices + insn->subdev;
808 DPRINTK("no async\n");
812 if (!s->async->inttrig) {
813 DPRINTK("no inttrig\n");
817 ret = s->async->inttrig(dev, s, insn->data[0]);
822 DPRINTK("invalid insn\n");
827 /* a subdevice instruction */
828 unsigned int maxdata;
830 if (insn->subdev >= dev->n_subdevices) {
831 DPRINTK("subdevice %d out of range\n", insn->subdev);
835 s = dev->subdevices + insn->subdev;
837 if (s->type == COMEDI_SUBD_UNUSED) {
838 DPRINTK("%d not usable subdevice\n", insn->subdev);
843 /* are we locked? (ioctl lock) */
844 if (s->lock && s->lock != file) {
845 DPRINTK("device locked\n");
850 ret = check_chanlist(s, 1, &insn->chanspec);
853 DPRINTK("bad chanspec\n");
861 /* This looks arbitrary. It is. */
862 s->busy = &parse_insn;
863 switch (insn->insn) {
865 ret = s->insn_read(dev, s, insn, data);
868 maxdata = s->maxdata_list
869 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
871 for (i = 0; i < insn->n; ++i) {
872 if (data[i] > maxdata) {
874 DPRINTK("bad data value(s)\n");
879 ret = s->insn_write(dev, s, insn, data);
886 ret = s->insn_bits(dev, s, insn, data);
889 ret = check_insn_config_length(insn, data);
892 ret = s->insn_config(dev, s, insn, data);
908 * synchronous instructions
914 * comedi_insn struct at arg
920 static int do_insn_ioctl(comedi_device *dev, void *arg, void *file)
923 unsigned int *data = NULL;
926 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
932 if (copy_from_user(&insn, arg, sizeof(comedi_insn))) {
937 /* This is where the behavior of insn and insnlist deviate. */
938 if (insn.n > MAX_SAMPLES)
939 insn.n = MAX_SAMPLES;
940 if (insn.insn & INSN_MASK_WRITE) {
941 if (copy_from_user(data, insn.data, insn.n * sizeof(unsigned int))) {
946 ret = parse_insn(dev, &insn, data, file);
949 if (insn.insn & INSN_MASK_READ) {
950 if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) {
968 pointer to cmd structure
975 modified cmd structure at arg
978 static int do_cmd_ioctl(comedi_device *dev, void *arg, void *file)
984 unsigned int *chanlist_saver = NULL;
986 if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
987 DPRINTK("bad cmd address\n");
990 /* save user's chanlist pointer so it can be restored later */
991 chanlist_saver = user_cmd.chanlist;
993 if (user_cmd.subdev >= dev->n_subdevices) {
994 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
998 s = dev->subdevices + user_cmd.subdev;
1001 if (s->type == COMEDI_SUBD_UNUSED) {
1002 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1006 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1007 DPRINTK("subdevice %i does not support commands\n",
1012 /* are we locked? (ioctl lock) */
1013 if (s->lock && s->lock != file) {
1014 DPRINTK("subdevice locked\n");
1020 DPRINTK("subdevice busy\n");
1025 /* make sure channel/gain list isn't too long */
1026 if (user_cmd.chanlist_len > s->len_chanlist) {
1027 DPRINTK("channel/gain list too long %u > %d\n",
1028 user_cmd.chanlist_len, s->len_chanlist);
1033 /* make sure channel/gain list isn't too short */
1034 if (user_cmd.chanlist_len < 1) {
1035 DPRINTK("channel/gain list too short %u < 1\n",
1036 user_cmd.chanlist_len);
1041 kfree(async->cmd.chanlist);
1042 async->cmd = user_cmd;
1043 async->cmd.data = NULL;
1044 /* load channel/gain list */
1045 async->cmd.chanlist =
1046 kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1047 if (!async->cmd.chanlist) {
1048 DPRINTK("allocation failed\n");
1053 if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1054 async->cmd.chanlist_len * sizeof(int))) {
1055 DPRINTK("fault reading chanlist\n");
1060 /* make sure each element in channel/gain list is valid */
1061 ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1063 DPRINTK("bad chanlist\n");
1067 ret = s->do_cmdtest(dev, s, &async->cmd);
1069 if (async->cmd.flags & TRIG_BOGUS || ret) {
1070 DPRINTK("test returned %d\n", ret);
1071 user_cmd = async->cmd;
1072 /* restore chanlist pointer before copying back */
1073 user_cmd.chanlist = chanlist_saver;
1074 user_cmd.data = NULL;
1075 if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
1076 DPRINTK("fault writing cmd\n");
1084 if (!async->prealloc_bufsz) {
1086 DPRINTK("no buffer (?)\n");
1090 comedi_reset_async_buf(async);
1093 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1095 if (async->cmd.flags & TRIG_WAKE_EOS)
1096 async->cb_mask |= COMEDI_CB_EOS;
1098 comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1100 #ifdef CONFIG_COMEDI_RT
1101 if (async->cmd.flags & TRIG_RT) {
1102 if (comedi_switch_to_rt(dev) == 0)
1103 comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT);
1107 ret = s->do_cmd(dev, s);
1112 do_become_nonbusy(dev, s);
1119 command testing ioctl
1122 pointer to cmd structure
1125 cmd structure at arg
1129 modified cmd structure at arg
1132 static int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file)
1134 comedi_cmd user_cmd;
1135 comedi_subdevice *s;
1137 unsigned int *chanlist = NULL;
1138 unsigned int *chanlist_saver = NULL;
1140 if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
1141 DPRINTK("bad cmd address\n");
1144 /* save user's chanlist pointer so it can be restored later */
1145 chanlist_saver = user_cmd.chanlist;
1147 if (user_cmd.subdev >= dev->n_subdevices) {
1148 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1152 s = dev->subdevices + user_cmd.subdev;
1153 if (s->type == COMEDI_SUBD_UNUSED) {
1154 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1158 if (!s->do_cmd || !s->do_cmdtest) {
1159 DPRINTK("subdevice %i does not support commands\n",
1164 /* make sure channel/gain list isn't too long */
1165 if (user_cmd.chanlist_len > s->len_chanlist) {
1166 DPRINTK("channel/gain list too long %d > %d\n",
1167 user_cmd.chanlist_len, s->len_chanlist);
1172 /* load channel/gain list */
1173 if (user_cmd.chanlist) {
1175 kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1177 DPRINTK("allocation failed\n");
1182 if (copy_from_user(chanlist, user_cmd.chanlist,
1183 user_cmd.chanlist_len * sizeof(int))) {
1184 DPRINTK("fault reading chanlist\n");
1189 /* make sure each element in channel/gain list is valid */
1190 ret = check_chanlist(s, user_cmd.chanlist_len, chanlist);
1192 DPRINTK("bad chanlist\n");
1196 user_cmd.chanlist = chanlist;
1199 ret = s->do_cmdtest(dev, s, &user_cmd);
1201 /* restore chanlist pointer before copying back */
1202 user_cmd.chanlist = chanlist_saver;
1204 if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
1205 DPRINTK("bad cmd address\n");
1230 static int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file)
1233 unsigned long flags;
1234 comedi_subdevice *s;
1236 if (arg >= dev->n_subdevices)
1238 s = dev->subdevices + arg;
1240 comedi_spin_lock_irqsave(&s->spin_lock, flags);
1241 if (s->busy || s->lock)
1245 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
1252 ret = s->lock_f(dev, s);
1271 This function isn't protected by the semaphore, since
1272 we already own the lock.
1274 static int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file)
1276 comedi_subdevice *s;
1278 if (arg >= dev->n_subdevices)
1280 s = dev->subdevices + arg;
1285 if (s->lock && s->lock != file)
1288 if (s->lock == file) {
1302 cancel acquisition ioctl
1314 static int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file)
1316 comedi_subdevice *s;
1318 if (arg >= dev->n_subdevices)
1320 s = dev->subdevices + arg;
1321 if (s->async == NULL)
1324 if (s->lock && s->lock != file)
1330 if (s->busy != file)
1333 return do_cancel(dev, s);
1338 instructs driver to synchronize buffers
1350 static int do_poll_ioctl(comedi_device *dev, unsigned int arg, void *file)
1352 comedi_subdevice *s;
1354 if (arg >= dev->n_subdevices)
1356 s = dev->subdevices + arg;
1358 if (s->lock && s->lock != file)
1364 if (s->busy != file)
1368 return s->poll(dev, s);
1373 static int do_cancel(comedi_device *dev, comedi_subdevice *s)
1377 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1378 ret = s->cancel(dev, s);
1380 do_become_nonbusy(dev, s);
1385 void comedi_unmap(struct vm_area_struct *area)
1387 comedi_async *async;
1390 async = area->vm_private_data;
1391 dev = async->subdevice->device;
1393 mutex_lock(&dev->mutex);
1394 async->mmap_count--;
1395 mutex_unlock(&dev->mutex);
1398 static struct vm_operations_struct comedi_vm_ops = {
1399 .close = comedi_unmap,
1402 static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1404 const unsigned minor = iminor(file->f_dentry->d_inode);
1405 struct comedi_device_file_info *dev_file_info =
1406 comedi_get_device_file_info(minor);
1407 comedi_device *dev = dev_file_info->device;
1408 comedi_async *async = NULL;
1409 unsigned long start = vma->vm_start;
1414 comedi_subdevice *s;
1416 mutex_lock(&dev->mutex);
1417 if (!dev->attached) {
1418 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1422 if (vma->vm_flags & VM_WRITE)
1423 s = comedi_get_write_subdevice(dev_file_info);
1425 s = comedi_get_read_subdevice(dev_file_info);
1432 if (async == NULL) {
1437 if (vma->vm_pgoff != 0) {
1438 DPRINTK("comedi: mmap() offset must be 0.\n");
1443 size = vma->vm_end - vma->vm_start;
1444 if (size > async->prealloc_bufsz) {
1448 if (size & (~PAGE_MASK)) {
1453 n_pages = size >> PAGE_SHIFT;
1454 for (i = 0; i < n_pages; ++i) {
1455 if (remap_pfn_range(vma, start,
1456 page_to_pfn(virt_to_page(async->
1459 PAGE_SIZE, PAGE_SHARED)) {
1466 vma->vm_ops = &comedi_vm_ops;
1467 vma->vm_private_data = async;
1469 async->mmap_count++;
1473 mutex_unlock(&dev->mutex);
1477 static unsigned int comedi_poll(struct file *file, poll_table *wait)
1479 unsigned int mask = 0;
1480 const unsigned minor = iminor(file->f_dentry->d_inode);
1481 struct comedi_device_file_info *dev_file_info =
1482 comedi_get_device_file_info(minor);
1483 comedi_device *dev = dev_file_info->device;
1484 comedi_subdevice *read_subdev;
1485 comedi_subdevice *write_subdev;
1487 mutex_lock(&dev->mutex);
1488 if (!dev->attached) {
1489 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1490 mutex_unlock(&dev->mutex);
1495 read_subdev = comedi_get_read_subdevice(dev_file_info);
1497 poll_wait(file, &read_subdev->async->wait_head, wait);
1498 if (!read_subdev->busy
1499 || comedi_buf_read_n_available(read_subdev->async) > 0
1500 || !(comedi_get_subdevice_runflags(read_subdev) &
1502 mask |= POLLIN | POLLRDNORM;
1505 write_subdev = comedi_get_write_subdevice(dev_file_info);
1507 poll_wait(file, &write_subdev->async->wait_head, wait);
1508 comedi_buf_write_alloc(write_subdev->async,
1509 write_subdev->async->prealloc_bufsz);
1510 if (!write_subdev->busy
1511 || !(comedi_get_subdevice_runflags(write_subdev) &
1513 || comedi_buf_write_n_allocated(write_subdev->async) >=
1514 bytes_per_sample(write_subdev->async->subdevice)) {
1515 mask |= POLLOUT | POLLWRNORM;
1519 mutex_unlock(&dev->mutex);
1523 static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
1526 comedi_subdevice *s;
1527 comedi_async *async;
1528 int n, m, count = 0, retval = 0;
1529 DECLARE_WAITQUEUE(wait, current);
1530 const unsigned minor = iminor(file->f_dentry->d_inode);
1531 struct comedi_device_file_info *dev_file_info =
1532 comedi_get_device_file_info(minor);
1533 comedi_device *dev = dev_file_info->device;
1535 if (!dev->attached) {
1536 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1541 s = comedi_get_write_subdevice(dev_file_info);
1556 if (s->busy != file) {
1560 add_wait_queue(&async->wait_head, &wait);
1561 while (nbytes > 0 && !retval) {
1562 set_current_state(TASK_INTERRUPTIBLE);
1567 if (async->buf_write_ptr + m > async->prealloc_bufsz)
1568 m = async->prealloc_bufsz - async->buf_write_ptr;
1569 comedi_buf_write_alloc(async, async->prealloc_bufsz);
1570 if (m > comedi_buf_write_n_allocated(async))
1571 m = comedi_buf_write_n_allocated(async);
1576 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1577 if (comedi_get_subdevice_runflags(s) &
1583 do_become_nonbusy(dev, s);
1586 if (file->f_flags & O_NONBLOCK) {
1590 if (signal_pending(current)) {
1591 retval = -ERESTARTSYS;
1597 if (s->busy != file) {
1604 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1610 comedi_buf_write_free(async, n);
1616 break; /* makes device work like a pipe */
1618 set_current_state(TASK_RUNNING);
1619 remove_wait_queue(&async->wait_head, &wait);
1622 return count ? count : retval;
1625 static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
1628 comedi_subdevice *s;
1629 comedi_async *async;
1630 int n, m, count = 0, retval = 0;
1631 DECLARE_WAITQUEUE(wait, current);
1632 const unsigned minor = iminor(file->f_dentry->d_inode);
1633 struct comedi_device_file_info *dev_file_info =
1634 comedi_get_device_file_info(minor);
1635 comedi_device *dev = dev_file_info->device;
1637 if (!dev->attached) {
1638 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1643 s = comedi_get_read_subdevice(dev_file_info);
1657 if (s->busy != file) {
1662 add_wait_queue(&async->wait_head, &wait);
1663 while (nbytes > 0 && !retval) {
1664 set_current_state(TASK_INTERRUPTIBLE);
1668 m = comedi_buf_read_n_available(async);
1669 /* printk("%d available\n",m); */
1670 if (async->buf_read_ptr + m > async->prealloc_bufsz)
1671 m = async->prealloc_bufsz - async->buf_read_ptr;
1672 /* printk("%d contiguous\n",m); */
1677 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1678 do_become_nonbusy(dev, s);
1679 if (comedi_get_subdevice_runflags(s) &
1687 if (file->f_flags & O_NONBLOCK) {
1691 if (signal_pending(current)) {
1692 retval = -ERESTARTSYS;
1700 if (s->busy != file) {
1706 m = copy_to_user(buf, async->prealloc_buf +
1707 async->buf_read_ptr, n);
1713 comedi_buf_read_alloc(async, n);
1714 comedi_buf_read_free(async, n);
1720 break; /* makes device work like a pipe */
1722 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1723 async->buf_read_count - async->buf_write_count == 0) {
1724 do_become_nonbusy(dev, s);
1726 set_current_state(TASK_RUNNING);
1727 remove_wait_queue(&async->wait_head, &wait);
1730 return count ? count : retval;
1734 This function restores a subdevice to an idle state.
1736 void do_become_nonbusy(comedi_device *dev, comedi_subdevice *s)
1738 comedi_async *async = s->async;
1740 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1741 #ifdef CONFIG_COMEDI_RT
1742 if (comedi_get_subdevice_runflags(s) & SRF_RT) {
1743 comedi_switch_to_non_rt(dev);
1744 comedi_set_subdevice_runflags(s, SRF_RT, 0);
1748 comedi_reset_async_buf(async);
1749 async->inttrig = NULL;
1752 "BUG: (?) do_become_nonbusy called with async=0\n");
1758 static int comedi_open(struct inode *inode, struct file *file)
1760 const unsigned minor = iminor(inode);
1761 struct comedi_device_file_info *dev_file_info =
1762 comedi_get_device_file_info(minor);
1763 comedi_device *dev = dev_file_info ? dev_file_info->device : NULL;
1766 DPRINTK("invalid minor number\n");
1770 /* This is slightly hacky, but we want module autoloading
1772 * case: user opens device, attached -> ok
1773 * case: user opens device, unattached, in_request_module=0 -> autoload
1774 * case: user opens device, unattached, in_request_module=1 -> fail
1775 * case: root opens device, attached -> ok
1776 * case: root opens device, unattached, in_request_module=1 -> ok
1777 * (typically called from modprobe)
1778 * case: root opens device, unattached, in_request_module=0 -> autoload
1780 * The last could be changed to "-> ok", which would deny root
1783 mutex_lock(&dev->mutex);
1786 if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
1787 DPRINTK("in request module\n");
1788 mutex_unlock(&dev->mutex);
1791 if (capable(CAP_SYS_MODULE) && dev->in_request_module)
1794 dev->in_request_module = 1;
1797 mutex_unlock(&dev->mutex);
1798 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1799 mutex_lock(&dev->mutex);
1802 dev->in_request_module = 0;
1804 if (!dev->attached && !capable(CAP_SYS_MODULE)) {
1805 DPRINTK("not attached and not CAP_SYS_MODULE\n");
1806 mutex_unlock(&dev->mutex);
1810 __module_get(THIS_MODULE);
1812 if (dev->attached) {
1813 if (!try_module_get(dev->driver->module)) {
1814 module_put(THIS_MODULE);
1815 mutex_unlock(&dev->mutex);
1820 if (dev->attached && dev->use_count == 0 && dev->open)
1825 mutex_unlock(&dev->mutex);
1830 static int comedi_close(struct inode *inode, struct file *file)
1832 const unsigned minor = iminor(inode);
1833 struct comedi_device_file_info *dev_file_info =
1834 comedi_get_device_file_info(minor);
1835 comedi_device *dev = dev_file_info->device;
1836 comedi_subdevice *s = NULL;
1839 mutex_lock(&dev->mutex);
1841 if (dev->subdevices) {
1842 for (i = 0; i < dev->n_subdevices; i++) {
1843 s = dev->subdevices + i;
1845 if (s->busy == file)
1847 if (s->lock == file)
1851 if (dev->attached && dev->use_count == 1 && dev->close)
1854 module_put(THIS_MODULE);
1856 module_put(dev->driver->module);
1860 mutex_unlock(&dev->mutex);
1862 if (file->f_flags & FASYNC)
1863 comedi_fasync(-1, file, 0);
1868 static int comedi_fasync(int fd, struct file *file, int on)
1870 const unsigned minor = iminor(file->f_dentry->d_inode);
1871 struct comedi_device_file_info *dev_file_info =
1872 comedi_get_device_file_info(minor);
1874 comedi_device *dev = dev_file_info->device;
1876 return fasync_helper(fd, file, on, &dev->async_queue);
1879 const struct file_operations comedi_fops = {
1880 .owner = THIS_MODULE,
1881 #ifdef HAVE_UNLOCKED_IOCTL
1882 .unlocked_ioctl = comedi_unlocked_ioctl,
1884 .ioctl = comedi_ioctl,
1886 #ifdef HAVE_COMPAT_IOCTL
1887 .compat_ioctl = comedi_compat_ioctl,
1889 .open = comedi_open,
1890 .release = comedi_close,
1891 .read = comedi_read,
1892 .write = comedi_write,
1893 .mmap = comedi_mmap,
1894 .poll = comedi_poll,
1895 .fasync = comedi_fasync,
1898 struct class *comedi_class;
1899 static struct cdev comedi_cdev;
1901 static void comedi_cleanup_legacy_minors(void)
1905 for (i = 0; i < comedi_num_legacy_minors; i++)
1906 comedi_free_board_minor(i);
1909 static int __init comedi_init(void)
1914 printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1915 " - http://www.comedi.org\n");
1917 if (comedi_num_legacy_minors < 0 ||
1918 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1919 printk(KERN_ERR "comedi: error: invalid value for module "
1920 "parameter \"comedi_num_legacy_minors\". Valid values "
1921 "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1926 * comedi is unusable if both comedi_autoconfig and
1927 * comedi_num_legacy_minors are zero, so we might as well adjust the
1928 * defaults in that case
1930 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1931 comedi_num_legacy_minors = 16;
1933 memset(comedi_file_info_table, 0,
1934 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1936 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1937 COMEDI_NUM_MINORS, "comedi");
1940 cdev_init(&comedi_cdev, &comedi_fops);
1941 comedi_cdev.owner = THIS_MODULE;
1942 kobject_set_name(&comedi_cdev.kobj, "comedi");
1943 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1944 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1948 comedi_class = class_create(THIS_MODULE, "comedi");
1949 if (IS_ERR(comedi_class)) {
1950 printk("comedi: failed to create class");
1951 cdev_del(&comedi_cdev);
1952 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1954 return PTR_ERR(comedi_class);
1957 /* XXX requires /proc interface */
1960 /* create devices files for legacy/manual use */
1961 for (i = 0; i < comedi_num_legacy_minors; i++) {
1963 minor = comedi_alloc_board_minor(NULL);
1965 comedi_cleanup_legacy_minors();
1966 cdev_del(&comedi_cdev);
1967 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1975 comedi_register_ioctl32();
1980 static void __exit comedi_cleanup(void)
1984 comedi_cleanup_legacy_minors();
1985 for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1986 BUG_ON(comedi_file_info_table[i]);
1989 class_destroy(comedi_class);
1990 cdev_del(&comedi_cdev);
1991 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1993 comedi_proc_cleanup();
1995 comedi_rt_cleanup();
1997 comedi_unregister_ioctl32();
2000 module_init(comedi_init);
2001 module_exit(comedi_cleanup);
2003 void comedi_error(const comedi_device *dev, const char *s)
2005 rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
2009 void comedi_event(comedi_device *dev, comedi_subdevice *s)
2011 comedi_async *async = s->async;
2012 unsigned runflags = 0;
2013 unsigned runflags_mask = 0;
2015 /* DPRINTK("comedi_event 0x%x\n",mask); */
2017 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2021 events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2022 runflags_mask |= SRF_RUNNING;
2024 /* remember if an error event has occured, so an error
2025 * can be returned the next time the user does a read() */
2026 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2027 runflags_mask |= SRF_ERROR;
2028 runflags |= SRF_ERROR;
2030 if (runflags_mask) {
2031 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2032 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2035 if (async->cb_mask & s->async->events) {
2036 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2039 #ifdef CONFIG_COMEDI_RT
2041 comedi_rt_pend_wakeup(&async->wait_head);
2044 ("BUG: comedi_event() code unreachable\n");
2047 wake_up_interruptible(&async->wait_head);
2048 if (s->subdev_flags & SDF_CMD_READ) {
2049 kill_fasync(&dev->async_queue, SIGIO,
2052 if (s->subdev_flags & SDF_CMD_WRITE) {
2053 kill_fasync(&dev->async_queue, SIGIO,
2059 async->cb_func(s->async->events, async->cb_arg);
2060 /* XXX bug here. If subdevice A is rt, and
2061 * subdevice B tries to callback to a normal
2062 * linux kernel function, it will be at the
2063 * wrong priority. Since this isn't very
2064 * common, I'm not going to worry about it. */
2067 s->async->events = 0;
2070 void comedi_set_subdevice_runflags(comedi_subdevice *s, unsigned mask,
2073 unsigned long flags;
2075 comedi_spin_lock_irqsave(&s->spin_lock, flags);
2076 s->runflags &= ~mask;
2077 s->runflags |= (bits & mask);
2078 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2081 unsigned comedi_get_subdevice_runflags(comedi_subdevice *s)
2083 unsigned long flags;
2086 comedi_spin_lock_irqsave(&s->spin_lock, flags);
2087 runflags = s->runflags;
2088 comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2092 static int is_device_busy(comedi_device *dev)
2094 comedi_subdevice *s;
2100 for (i = 0; i < dev->n_subdevices; i++) {
2101 s = dev->subdevices + i;
2104 if (s->async && s->async->mmap_count)
2111 void comedi_device_init(comedi_device *dev)
2113 memset(dev, 0, sizeof(comedi_device));
2114 spin_lock_init(&dev->spinlock);
2115 mutex_init(&dev->mutex);
2119 void comedi_device_cleanup(comedi_device *dev)
2123 mutex_lock(&dev->mutex);
2124 comedi_device_detach(dev);
2125 mutex_unlock(&dev->mutex);
2126 mutex_destroy(&dev->mutex);
2129 int comedi_alloc_board_minor(struct device *hardware_device)
2131 unsigned long flags;
2132 struct comedi_device_file_info *info;
2133 device_create_result_type *csdev;
2136 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2139 info->device = kzalloc(sizeof(comedi_device), GFP_KERNEL);
2140 if (info->device == NULL) {
2144 comedi_device_init(info->device);
2145 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2146 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2147 if (comedi_file_info_table[i] == NULL) {
2148 comedi_file_info_table[i] = info;
2152 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2153 if (i == COMEDI_NUM_BOARD_MINORS) {
2154 comedi_device_cleanup(info->device);
2155 kfree(info->device);
2158 ("comedi: error: ran out of minor numbers for board device files.\n");
2161 info->device->minor = i;
2162 csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2163 MKDEV(COMEDI_MAJOR, i), NULL,
2164 hardware_device, "comedi%i", i);
2166 info->device->class_dev = csdev;
2171 void comedi_free_board_minor(unsigned minor)
2173 unsigned long flags;
2174 struct comedi_device_file_info *info;
2176 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2177 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2178 info = comedi_file_info_table[minor];
2179 comedi_file_info_table[minor] = NULL;
2180 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2183 comedi_device *dev = info->device;
2185 if (dev->class_dev) {
2186 device_destroy(comedi_class,
2187 MKDEV(COMEDI_MAJOR, dev->minor));
2189 comedi_device_cleanup(dev);
2196 int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s)
2198 unsigned long flags;
2199 struct comedi_device_file_info *info;
2200 device_create_result_type *csdev;
2203 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2207 info->read_subdevice = s;
2208 info->write_subdevice = s;
2209 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2210 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2211 if (comedi_file_info_table[i] == NULL) {
2212 comedi_file_info_table[i] = info;
2216 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2217 if (i == COMEDI_NUM_MINORS) {
2220 ("comedi: error: ran out of minor numbers for board device files.\n");
2224 csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2225 MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2226 "comedi%i_subd%i", dev->minor,
2227 (int)(s - dev->subdevices));
2229 s->class_dev = csdev;
2234 void comedi_free_subdevice_minor(comedi_subdevice *s)
2236 unsigned long flags;
2237 struct comedi_device_file_info *info;
2244 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2245 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2247 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2248 info = comedi_file_info_table[s->minor];
2249 comedi_file_info_table[s->minor] = NULL;
2250 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2253 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2254 s->class_dev = NULL;
2259 struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2261 unsigned long flags;
2262 struct comedi_device_file_info *info;
2264 BUG_ON(minor >= COMEDI_NUM_MINORS);
2265 comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2266 info = comedi_file_info_table[minor];
2267 comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);