Merge branch 'mini2440-dev-unlikely' into mini2440-dev
[linux-2.6/mini2440.git] / drivers / staging / comedi / comedi_fops.c
blobaaad76e0a76a351f6b26a508982dbbfa9787c7a9
1 /*
2 comedi/comedi_fops.c
3 comedi kernel module
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.
24 #undef DEBUG
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>
37 #include <linux/mm.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>
44 #include <linux/fs.h>
45 #include "comedidev.h"
46 #include <linux/cdev.h>
47 #include <linux/stat.h>
49 #include <linux/io.h>
50 #include <linux/uaccess.h>
52 /* #include "kvmem.h" */
54 MODULE_AUTHOR("http://www.comedi.org");
55 MODULE_DESCRIPTION("Comedi core module");
56 MODULE_LICENSE("GPL");
58 #ifdef CONFIG_COMEDI_DEBUG
59 int comedi_debug;
60 module_param(comedi_debug, int, 0644);
61 #endif
63 int comedi_autoconfig = 1;
64 module_param(comedi_autoconfig, bool, 0444);
66 int comedi_num_legacy_minors = 0;
67 module_param(comedi_num_legacy_minors, int, 0444);
69 static DEFINE_SPINLOCK(comedi_file_info_table_lock);
70 static struct comedi_device_file_info
71 *comedi_file_info_table[COMEDI_NUM_MINORS];
73 static int do_devconfig_ioctl(struct comedi_device *dev,
74 struct comedi_devconfig *arg);
75 static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
76 static int do_devinfo_ioctl(struct comedi_device *dev,
77 struct comedi_devinfo *arg, struct file *file);
78 static int do_subdinfo_ioctl(struct comedi_device *dev,
79 struct comedi_subdinfo *arg, void *file);
80 static int do_chaninfo_ioctl(struct comedi_device *dev,
81 struct comedi_chaninfo *arg);
82 static int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
83 static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
84 static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
85 void *file);
86 static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
87 void *file);
88 static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
89 void *file);
90 static int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
91 static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
92 static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
93 static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
94 void *file);
96 extern void do_become_nonbusy(struct comedi_device *dev,
97 struct comedi_subdevice *s);
98 static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
100 static int comedi_fasync(int fd, struct file *file, int on);
102 static int is_device_busy(struct comedi_device *dev);
103 static int resize_async_buffer(struct comedi_device *dev,
104 struct comedi_subdevice *s,
105 struct comedi_async *async, unsigned new_size);
107 /* declarations for sysfs attribute files */
108 static struct device_attribute dev_attr_max_read_buffer_kb;
109 static struct device_attribute dev_attr_read_buffer_kb;
110 static struct device_attribute dev_attr_max_write_buffer_kb;
111 static struct device_attribute dev_attr_write_buffer_kb;
113 #ifdef HAVE_UNLOCKED_IOCTL
114 static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
115 unsigned long arg)
116 #else
117 static int comedi_ioctl(struct inode *inode, struct file *file,
118 unsigned int cmd, unsigned long arg)
119 #endif
121 const unsigned minor = iminor(file->f_dentry->d_inode);
122 struct comedi_device_file_info *dev_file_info =
123 comedi_get_device_file_info(minor);
124 struct comedi_device *dev;
125 int rc;
127 if (dev_file_info == NULL || dev_file_info->device == NULL)
128 return -ENODEV;
129 dev = dev_file_info->device;
131 mutex_lock(&dev->mutex);
133 /* Device config is special, because it must work on
134 * an unconfigured device. */
135 if (cmd == COMEDI_DEVCONFIG) {
136 rc = do_devconfig_ioctl(dev, (void *)arg);
137 goto done;
140 if (!dev->attached) {
141 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
142 rc = -ENODEV;
143 goto done;
146 switch (cmd) {
147 case COMEDI_BUFCONFIG:
148 rc = do_bufconfig_ioctl(dev, (void *)arg);
149 break;
150 case COMEDI_DEVINFO:
151 rc = do_devinfo_ioctl(dev, (void *)arg, file);
152 break;
153 case COMEDI_SUBDINFO:
154 rc = do_subdinfo_ioctl(dev, (void *)arg, file);
155 break;
156 case COMEDI_CHANINFO:
157 rc = do_chaninfo_ioctl(dev, (void *)arg);
158 break;
159 case COMEDI_RANGEINFO:
160 rc = do_rangeinfo_ioctl(dev, (void *)arg);
161 break;
162 case COMEDI_BUFINFO:
163 rc = do_bufinfo_ioctl(dev, (void *)arg);
164 break;
165 case COMEDI_LOCK:
166 rc = do_lock_ioctl(dev, arg, file);
167 break;
168 case COMEDI_UNLOCK:
169 rc = do_unlock_ioctl(dev, arg, file);
170 break;
171 case COMEDI_CANCEL:
172 rc = do_cancel_ioctl(dev, arg, file);
173 break;
174 case COMEDI_CMD:
175 rc = do_cmd_ioctl(dev, (void *)arg, file);
176 break;
177 case COMEDI_CMDTEST:
178 rc = do_cmdtest_ioctl(dev, (void *)arg, file);
179 break;
180 case COMEDI_INSNLIST:
181 rc = do_insnlist_ioctl(dev, (void *)arg, file);
182 break;
183 case COMEDI_INSN:
184 rc = do_insn_ioctl(dev, (void *)arg, file);
185 break;
186 case COMEDI_POLL:
187 rc = do_poll_ioctl(dev, arg, file);
188 break;
189 default:
190 rc = -ENOTTY;
191 break;
194 done:
195 mutex_unlock(&dev->mutex);
196 return rc;
200 COMEDI_DEVCONFIG
201 device config ioctl
203 arg:
204 pointer to devconfig structure
206 reads:
207 devconfig structure at arg
209 writes:
210 none
212 static int do_devconfig_ioctl(struct comedi_device *dev,
213 struct comedi_devconfig *arg)
215 struct comedi_devconfig it;
216 int ret;
217 unsigned char *aux_data = NULL;
218 int aux_len;
220 if (!capable(CAP_SYS_ADMIN))
221 return -EPERM;
223 if (arg == NULL) {
224 if (is_device_busy(dev))
225 return -EBUSY;
226 if (dev->attached) {
227 struct module *driver_module = dev->driver->module;
228 comedi_device_detach(dev);
229 module_put(driver_module);
231 return 0;
234 if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
235 return -EFAULT;
237 it.board_name[COMEDI_NAMELEN - 1] = 0;
239 if (comedi_aux_data(it.options, 0) &&
240 it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
241 int bit_shift;
242 aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
243 if (aux_len < 0)
244 return -EFAULT;
246 aux_data = vmalloc(aux_len);
247 if (!aux_data)
248 return -ENOMEM;
250 if (copy_from_user(aux_data,
251 comedi_aux_data(it.options, 0), aux_len)) {
252 vfree(aux_data);
253 return -EFAULT;
255 it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
256 (unsigned long)aux_data;
257 if (sizeof(void *) > sizeof(int)) {
258 bit_shift = sizeof(int) * 8;
259 it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
260 ((unsigned long)aux_data) >> bit_shift;
261 } else
262 it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
265 ret = comedi_device_attach(dev, &it);
266 if (ret == 0) {
267 if (!try_module_get(dev->driver->module)) {
268 comedi_device_detach(dev);
269 return -ENOSYS;
273 if (aux_data)
274 vfree(aux_data);
276 return ret;
280 COMEDI_BUFCONFIG
281 buffer configuration ioctl
283 arg:
284 pointer to bufconfig structure
286 reads:
287 bufconfig at arg
289 writes:
290 modified bufconfig at arg
293 static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)
295 struct comedi_bufconfig bc;
296 struct comedi_async *async;
297 struct comedi_subdevice *s;
298 int retval = 0;
300 if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
301 return -EFAULT;
303 if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
304 return -EINVAL;
306 s = dev->subdevices + bc.subdevice;
307 async = s->async;
309 if (!async) {
310 DPRINTK("subdevice does not have async capability\n");
311 bc.size = 0;
312 bc.maximum_size = 0;
313 goto copyback;
316 if (bc.maximum_size) {
317 if (!capable(CAP_SYS_ADMIN))
318 return -EPERM;
320 async->max_bufsize = bc.maximum_size;
323 if (bc.size) {
324 retval = resize_async_buffer(dev, s, async, bc.size);
325 if (retval < 0)
326 return retval;
329 bc.size = async->prealloc_bufsz;
330 bc.maximum_size = async->max_bufsize;
332 copyback:
333 if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
334 return -EFAULT;
336 return 0;
340 COMEDI_DEVINFO
341 device info ioctl
343 arg:
344 pointer to devinfo structure
346 reads:
347 none
349 writes:
350 devinfo structure
353 static int do_devinfo_ioctl(struct comedi_device *dev,
354 struct comedi_devinfo *arg, struct file *file)
356 struct comedi_devinfo devinfo;
357 const unsigned minor = iminor(file->f_dentry->d_inode);
358 struct comedi_device_file_info *dev_file_info =
359 comedi_get_device_file_info(minor);
360 struct comedi_subdevice *read_subdev =
361 comedi_get_read_subdevice(dev_file_info);
362 struct comedi_subdevice *write_subdev =
363 comedi_get_write_subdevice(dev_file_info);
365 memset(&devinfo, 0, sizeof(devinfo));
367 /* fill devinfo structure */
368 devinfo.version_code = COMEDI_VERSION_CODE;
369 devinfo.n_subdevs = dev->n_subdevices;
370 memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
371 memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
373 if (read_subdev)
374 devinfo.read_subdevice = read_subdev - dev->subdevices;
375 else
376 devinfo.read_subdevice = -1;
378 if (write_subdev)
379 devinfo.write_subdevice = write_subdev - dev->subdevices;
380 else
381 devinfo.write_subdevice = -1;
383 if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
384 return -EFAULT;
386 return 0;
390 COMEDI_SUBDINFO
391 subdevice info ioctl
393 arg:
394 pointer to array of subdevice info structures
396 reads:
397 none
399 writes:
400 array of subdevice info structures at arg
403 static int do_subdinfo_ioctl(struct comedi_device *dev,
404 struct comedi_subdinfo *arg, void *file)
406 int ret, i;
407 struct comedi_subdinfo *tmp, *us;
408 struct comedi_subdevice *s;
410 tmp =
411 kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
412 GFP_KERNEL);
413 if (!tmp)
414 return -ENOMEM;
416 /* fill subdinfo structs */
417 for (i = 0; i < dev->n_subdevices; i++) {
418 s = dev->subdevices + i;
419 us = tmp + i;
421 us->type = s->type;
422 us->n_chan = s->n_chan;
423 us->subd_flags = s->subdev_flags;
424 if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
425 us->subd_flags |= SDF_RUNNING;
426 #define TIMER_nanosec 5 /* backwards compatibility */
427 us->timer_type = TIMER_nanosec;
428 us->len_chanlist = s->len_chanlist;
429 us->maxdata = s->maxdata;
430 if (s->range_table) {
431 us->range_type =
432 (i << 24) | (0 << 16) | (s->range_table->length);
433 } else {
434 us->range_type = 0; /* XXX */
436 us->flags = s->flags;
438 if (s->busy)
439 us->subd_flags |= SDF_BUSY;
440 if (s->busy == file)
441 us->subd_flags |= SDF_BUSY_OWNER;
442 if (s->lock)
443 us->subd_flags |= SDF_LOCKED;
444 if (s->lock == file)
445 us->subd_flags |= SDF_LOCK_OWNER;
446 if (!s->maxdata && s->maxdata_list)
447 us->subd_flags |= SDF_MAXDATA;
448 if (s->flaglist)
449 us->subd_flags |= SDF_FLAGS;
450 if (s->range_table_list)
451 us->subd_flags |= SDF_RANGETYPE;
452 if (s->do_cmd)
453 us->subd_flags |= SDF_CMD;
455 if (s->insn_bits != &insn_inval)
456 us->insn_bits_support = COMEDI_SUPPORTED;
457 else
458 us->insn_bits_support = COMEDI_UNSUPPORTED;
460 us->settling_time_0 = s->settling_time_0;
463 ret = copy_to_user(arg, tmp,
464 dev->n_subdevices * sizeof(struct comedi_subdinfo));
466 kfree(tmp);
468 return ret ? -EFAULT : 0;
472 COMEDI_CHANINFO
473 subdevice info ioctl
475 arg:
476 pointer to chaninfo structure
478 reads:
479 chaninfo structure at arg
481 writes:
482 arrays at elements of chaninfo structure
485 static int do_chaninfo_ioctl(struct comedi_device *dev,
486 struct comedi_chaninfo *arg)
488 struct comedi_subdevice *s;
489 struct comedi_chaninfo it;
491 if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
492 return -EFAULT;
494 if (it.subdev >= dev->n_subdevices)
495 return -EINVAL;
496 s = dev->subdevices + it.subdev;
498 if (it.maxdata_list) {
499 if (s->maxdata || !s->maxdata_list)
500 return -EINVAL;
501 if (copy_to_user(it.maxdata_list, s->maxdata_list,
502 s->n_chan * sizeof(unsigned int)))
503 return -EFAULT;
506 if (it.flaglist) {
507 if (!s->flaglist)
508 return -EINVAL;
509 if (copy_to_user(it.flaglist, s->flaglist,
510 s->n_chan * sizeof(unsigned int)))
511 return -EFAULT;
514 if (it.rangelist) {
515 int i;
517 if (!s->range_table_list)
518 return -EINVAL;
519 for (i = 0; i < s->n_chan; i++) {
520 int x;
522 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
523 (s->range_table_list[i]->length);
524 put_user(x, it.rangelist + i);
526 #if 0
527 if (copy_to_user(it.rangelist, s->range_type_list,
528 s->n_chan * sizeof(unsigned int)))
529 return -EFAULT;
530 #endif
533 return 0;
537 COMEDI_BUFINFO
538 buffer information ioctl
540 arg:
541 pointer to bufinfo structure
543 reads:
544 bufinfo at arg
546 writes:
547 modified bufinfo at arg
550 static int do_bufinfo_ioctl(struct comedi_device *dev, void *arg)
552 struct comedi_bufinfo bi;
553 struct comedi_subdevice *s;
554 struct comedi_async *async;
556 if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
557 return -EFAULT;
559 if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
560 return -EINVAL;
562 s = dev->subdevices + bi.subdevice;
563 async = s->async;
565 if (!async) {
566 DPRINTK("subdevice does not have async capability\n");
567 bi.buf_write_ptr = 0;
568 bi.buf_read_ptr = 0;
569 bi.buf_write_count = 0;
570 bi.buf_read_count = 0;
571 goto copyback;
574 if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
575 bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
576 comedi_buf_read_free(async, bi.bytes_read);
578 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
579 SRF_RUNNING))
580 && async->buf_write_count == async->buf_read_count) {
581 do_become_nonbusy(dev, s);
585 if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
586 bi.bytes_written =
587 comedi_buf_write_alloc(async, bi.bytes_written);
588 comedi_buf_write_free(async, bi.bytes_written);
591 bi.buf_write_count = async->buf_write_count;
592 bi.buf_write_ptr = async->buf_write_ptr;
593 bi.buf_read_count = async->buf_read_count;
594 bi.buf_read_ptr = async->buf_read_ptr;
596 copyback:
597 if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
598 return -EFAULT;
600 return 0;
603 static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
604 unsigned int *data, void *file);
606 * COMEDI_INSNLIST
607 * synchronous instructions
609 * arg:
610 * pointer to sync cmd structure
612 * reads:
613 * sync cmd struct at arg
614 * instruction list
615 * data (for writes)
617 * writes:
618 * data (for reads)
620 /* arbitrary limits */
621 #define MAX_SAMPLES 256
622 static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
624 struct comedi_insnlist insnlist;
625 struct comedi_insn *insns = NULL;
626 unsigned int *data = NULL;
627 int i = 0;
628 int ret = 0;
630 if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
631 return -EFAULT;
633 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
634 if (!data) {
635 DPRINTK("kmalloc failed\n");
636 ret = -ENOMEM;
637 goto error;
640 insns =
641 kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
642 if (!insns) {
643 DPRINTK("kmalloc failed\n");
644 ret = -ENOMEM;
645 goto error;
648 if (copy_from_user(insns, insnlist.insns,
649 sizeof(struct comedi_insn) * insnlist.n_insns)) {
650 DPRINTK("copy_from_user failed\n");
651 ret = -EFAULT;
652 goto error;
655 for (i = 0; i < insnlist.n_insns; i++) {
656 if (insns[i].n > MAX_SAMPLES) {
657 DPRINTK("number of samples too large\n");
658 ret = -EINVAL;
659 goto error;
661 if (insns[i].insn & INSN_MASK_WRITE) {
662 if (copy_from_user(data, insns[i].data,
663 insns[i].n * sizeof(unsigned int))) {
664 DPRINTK("copy_from_user failed\n");
665 ret = -EFAULT;
666 goto error;
669 ret = parse_insn(dev, insns + i, data, file);
670 if (ret < 0)
671 goto error;
672 if (insns[i].insn & INSN_MASK_READ) {
673 if (copy_to_user(insns[i].data, data,
674 insns[i].n * sizeof(unsigned int))) {
675 DPRINTK("copy_to_user failed\n");
676 ret = -EFAULT;
677 goto error;
680 if (need_resched())
681 schedule();
684 error:
685 kfree(insns);
686 kfree(data);
688 if (ret < 0)
689 return ret;
690 return i;
693 static int check_insn_config_length(struct comedi_insn *insn,
694 unsigned int *data)
696 if (insn->n < 1)
697 return -EINVAL;
699 switch (data[0]) {
700 case INSN_CONFIG_DIO_OUTPUT:
701 case INSN_CONFIG_DIO_INPUT:
702 case INSN_CONFIG_DISARM:
703 case INSN_CONFIG_RESET:
704 if (insn->n == 1)
705 return 0;
706 break;
707 case INSN_CONFIG_ARM:
708 case INSN_CONFIG_DIO_QUERY:
709 case INSN_CONFIG_BLOCK_SIZE:
710 case INSN_CONFIG_FILTER:
711 case INSN_CONFIG_SERIAL_CLOCK:
712 case INSN_CONFIG_BIDIRECTIONAL_DATA:
713 case INSN_CONFIG_ALT_SOURCE:
714 case INSN_CONFIG_SET_COUNTER_MODE:
715 case INSN_CONFIG_8254_READ_STATUS:
716 case INSN_CONFIG_SET_ROUTING:
717 case INSN_CONFIG_GET_ROUTING:
718 case INSN_CONFIG_GET_PWM_STATUS:
719 case INSN_CONFIG_PWM_SET_PERIOD:
720 case INSN_CONFIG_PWM_GET_PERIOD:
721 if (insn->n == 2)
722 return 0;
723 break;
724 case INSN_CONFIG_SET_GATE_SRC:
725 case INSN_CONFIG_GET_GATE_SRC:
726 case INSN_CONFIG_SET_CLOCK_SRC:
727 case INSN_CONFIG_GET_CLOCK_SRC:
728 case INSN_CONFIG_SET_OTHER_SRC:
729 case INSN_CONFIG_GET_COUNTER_STATUS:
730 case INSN_CONFIG_PWM_SET_H_BRIDGE:
731 case INSN_CONFIG_PWM_GET_H_BRIDGE:
732 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
733 if (insn->n == 3)
734 return 0;
735 break;
736 case INSN_CONFIG_PWM_OUTPUT:
737 case INSN_CONFIG_ANALOG_TRIG:
738 if (insn->n == 5)
739 return 0;
740 break;
741 /* by default we allow the insn since we don't have checks for
742 * all possible cases yet */
743 default:
744 printk("comedi: no check for data length of config insn id "
745 "%i is implemented.\n"
746 " Add a check to %s in %s.\n"
747 " Assuming n=%i is correct.\n", data[0], __func__,
748 __FILE__, insn->n);
749 return 0;
750 break;
752 return -EINVAL;
755 static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
756 unsigned int *data, void *file)
758 struct comedi_subdevice *s;
759 int ret = 0;
760 int i;
762 if (insn->insn & INSN_MASK_SPECIAL) {
763 /* a non-subdevice instruction */
765 switch (insn->insn) {
766 case INSN_GTOD:
768 struct timeval tv;
770 if (insn->n != 2) {
771 ret = -EINVAL;
772 break;
775 do_gettimeofday(&tv);
776 data[0] = tv.tv_sec;
777 data[1] = tv.tv_usec;
778 ret = 2;
780 break;
782 case INSN_WAIT:
783 if (insn->n != 1 || data[0] >= 100000) {
784 ret = -EINVAL;
785 break;
787 udelay(data[0] / 1000);
788 ret = 1;
789 break;
790 case INSN_INTTRIG:
791 if (insn->n != 1) {
792 ret = -EINVAL;
793 break;
795 if (insn->subdev >= dev->n_subdevices) {
796 DPRINTK("%d not usable subdevice\n",
797 insn->subdev);
798 ret = -EINVAL;
799 break;
801 s = dev->subdevices + insn->subdev;
802 if (!s->async) {
803 DPRINTK("no async\n");
804 ret = -EINVAL;
805 break;
807 if (!s->async->inttrig) {
808 DPRINTK("no inttrig\n");
809 ret = -EAGAIN;
810 break;
812 ret = s->async->inttrig(dev, s, insn->data[0]);
813 if (ret >= 0)
814 ret = 1;
815 break;
816 default:
817 DPRINTK("invalid insn\n");
818 ret = -EINVAL;
819 break;
821 } else {
822 /* a subdevice instruction */
823 unsigned int maxdata;
825 if (insn->subdev >= dev->n_subdevices) {
826 DPRINTK("subdevice %d out of range\n", insn->subdev);
827 ret = -EINVAL;
828 goto out;
830 s = dev->subdevices + insn->subdev;
832 if (s->type == COMEDI_SUBD_UNUSED) {
833 DPRINTK("%d not usable subdevice\n", insn->subdev);
834 ret = -EIO;
835 goto out;
838 /* are we locked? (ioctl lock) */
839 if (s->lock && s->lock != file) {
840 DPRINTK("device locked\n");
841 ret = -EACCES;
842 goto out;
845 ret = check_chanlist(s, 1, &insn->chanspec);
846 if (ret < 0) {
847 ret = -EINVAL;
848 DPRINTK("bad chanspec\n");
849 goto out;
852 if (s->busy) {
853 ret = -EBUSY;
854 goto out;
856 /* This looks arbitrary. It is. */
857 s->busy = &parse_insn;
858 switch (insn->insn) {
859 case INSN_READ:
860 ret = s->insn_read(dev, s, insn, data);
861 break;
862 case INSN_WRITE:
863 maxdata = s->maxdata_list
864 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
865 : s->maxdata;
866 for (i = 0; i < insn->n; ++i) {
867 if (data[i] > maxdata) {
868 ret = -EINVAL;
869 DPRINTK("bad data value(s)\n");
870 break;
873 if (ret == 0)
874 ret = s->insn_write(dev, s, insn, data);
875 break;
876 case INSN_BITS:
877 if (insn->n != 2) {
878 ret = -EINVAL;
879 break;
881 ret = s->insn_bits(dev, s, insn, data);
882 break;
883 case INSN_CONFIG:
884 ret = check_insn_config_length(insn, data);
885 if (ret)
886 break;
887 ret = s->insn_config(dev, s, insn, data);
888 break;
889 default:
890 ret = -EINVAL;
891 break;
894 s->busy = NULL;
897 out:
898 return ret;
902 * COMEDI_INSN
903 * synchronous instructions
905 * arg:
906 * pointer to insn
908 * reads:
909 * struct comedi_insn struct at arg
910 * data (for writes)
912 * writes:
913 * data (for reads)
915 static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
917 struct comedi_insn insn;
918 unsigned int *data = NULL;
919 int ret = 0;
921 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
922 if (!data) {
923 ret = -ENOMEM;
924 goto error;
927 if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
928 ret = -EFAULT;
929 goto error;
932 /* This is where the behavior of insn and insnlist deviate. */
933 if (insn.n > MAX_SAMPLES)
934 insn.n = MAX_SAMPLES;
935 if (insn.insn & INSN_MASK_WRITE) {
936 if (copy_from_user
937 (data, insn.data, insn.n * sizeof(unsigned int))) {
938 ret = -EFAULT;
939 goto error;
942 ret = parse_insn(dev, &insn, data, file);
943 if (ret < 0)
944 goto error;
945 if (insn.insn & INSN_MASK_READ) {
946 if (copy_to_user
947 (insn.data, data, insn.n * sizeof(unsigned int))) {
948 ret = -EFAULT;
949 goto error;
952 ret = insn.n;
954 error:
955 kfree(data);
957 return ret;
961 COMEDI_CMD
962 command ioctl
964 arg:
965 pointer to cmd structure
967 reads:
968 cmd structure at arg
969 channel/range list
971 writes:
972 modified cmd structure at arg
975 static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
977 struct comedi_cmd user_cmd;
978 struct comedi_subdevice *s;
979 struct comedi_async *async;
980 int ret = 0;
981 unsigned int *chanlist_saver = NULL;
983 if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
984 DPRINTK("bad cmd address\n");
985 return -EFAULT;
987 /* save user's chanlist pointer so it can be restored later */
988 chanlist_saver = user_cmd.chanlist;
990 if (user_cmd.subdev >= dev->n_subdevices) {
991 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
992 return -ENODEV;
995 s = dev->subdevices + user_cmd.subdev;
996 async = s->async;
998 if (s->type == COMEDI_SUBD_UNUSED) {
999 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1000 return -EIO;
1003 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1004 DPRINTK("subdevice %i does not support commands\n",
1005 user_cmd.subdev);
1006 return -EIO;
1009 /* are we locked? (ioctl lock) */
1010 if (s->lock && s->lock != file) {
1011 DPRINTK("subdevice locked\n");
1012 return -EACCES;
1015 /* are we busy? */
1016 if (s->busy) {
1017 DPRINTK("subdevice busy\n");
1018 return -EBUSY;
1020 s->busy = file;
1022 /* make sure channel/gain list isn't too long */
1023 if (user_cmd.chanlist_len > s->len_chanlist) {
1024 DPRINTK("channel/gain list too long %u > %d\n",
1025 user_cmd.chanlist_len, s->len_chanlist);
1026 ret = -EINVAL;
1027 goto cleanup;
1030 /* make sure channel/gain list isn't too short */
1031 if (user_cmd.chanlist_len < 1) {
1032 DPRINTK("channel/gain list too short %u < 1\n",
1033 user_cmd.chanlist_len);
1034 ret = -EINVAL;
1035 goto cleanup;
1038 kfree(async->cmd.chanlist);
1039 async->cmd = user_cmd;
1040 async->cmd.data = NULL;
1041 /* load channel/gain list */
1042 async->cmd.chanlist =
1043 kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1044 if (!async->cmd.chanlist) {
1045 DPRINTK("allocation failed\n");
1046 ret = -ENOMEM;
1047 goto cleanup;
1050 if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1051 async->cmd.chanlist_len * sizeof(int))) {
1052 DPRINTK("fault reading chanlist\n");
1053 ret = -EFAULT;
1054 goto cleanup;
1057 /* make sure each element in channel/gain list is valid */
1058 ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist);
1059 if (ret < 0) {
1060 DPRINTK("bad chanlist\n");
1061 goto cleanup;
1064 ret = s->do_cmdtest(dev, s, &async->cmd);
1066 if (async->cmd.flags & TRIG_BOGUS || ret) {
1067 DPRINTK("test returned %d\n", ret);
1068 user_cmd = async->cmd;
1069 /* restore chanlist pointer before copying back */
1070 user_cmd.chanlist = chanlist_saver;
1071 user_cmd.data = NULL;
1072 if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1073 DPRINTK("fault writing cmd\n");
1074 ret = -EFAULT;
1075 goto cleanup;
1077 ret = -EAGAIN;
1078 goto cleanup;
1081 if (!async->prealloc_bufsz) {
1082 ret = -ENOMEM;
1083 DPRINTK("no buffer (?)\n");
1084 goto cleanup;
1087 comedi_reset_async_buf(async);
1089 async->cb_mask =
1090 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1091 COMEDI_CB_OVERFLOW;
1092 if (async->cmd.flags & TRIG_WAKE_EOS)
1093 async->cb_mask |= COMEDI_CB_EOS;
1095 comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1097 ret = s->do_cmd(dev, s);
1098 if (ret == 0)
1099 return 0;
1101 cleanup:
1102 do_become_nonbusy(dev, s);
1104 return ret;
1108 COMEDI_CMDTEST
1109 command testing ioctl
1111 arg:
1112 pointer to cmd structure
1114 reads:
1115 cmd structure at arg
1116 channel/range list
1118 writes:
1119 modified cmd structure at arg
1122 static int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file)
1124 struct comedi_cmd user_cmd;
1125 struct comedi_subdevice *s;
1126 int ret = 0;
1127 unsigned int *chanlist = NULL;
1128 unsigned int *chanlist_saver = NULL;
1130 if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1131 DPRINTK("bad cmd address\n");
1132 return -EFAULT;
1134 /* save user's chanlist pointer so it can be restored later */
1135 chanlist_saver = user_cmd.chanlist;
1137 if (user_cmd.subdev >= dev->n_subdevices) {
1138 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1139 return -ENODEV;
1142 s = dev->subdevices + user_cmd.subdev;
1143 if (s->type == COMEDI_SUBD_UNUSED) {
1144 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1145 return -EIO;
1148 if (!s->do_cmd || !s->do_cmdtest) {
1149 DPRINTK("subdevice %i does not support commands\n",
1150 user_cmd.subdev);
1151 return -EIO;
1154 /* make sure channel/gain list isn't too long */
1155 if (user_cmd.chanlist_len > s->len_chanlist) {
1156 DPRINTK("channel/gain list too long %d > %d\n",
1157 user_cmd.chanlist_len, s->len_chanlist);
1158 ret = -EINVAL;
1159 goto cleanup;
1162 /* load channel/gain list */
1163 if (user_cmd.chanlist) {
1164 chanlist =
1165 kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1166 if (!chanlist) {
1167 DPRINTK("allocation failed\n");
1168 ret = -ENOMEM;
1169 goto cleanup;
1172 if (copy_from_user(chanlist, user_cmd.chanlist,
1173 user_cmd.chanlist_len * sizeof(int))) {
1174 DPRINTK("fault reading chanlist\n");
1175 ret = -EFAULT;
1176 goto cleanup;
1179 /* make sure each element in channel/gain list is valid */
1180 ret = check_chanlist(s, user_cmd.chanlist_len, chanlist);
1181 if (ret < 0) {
1182 DPRINTK("bad chanlist\n");
1183 goto cleanup;
1186 user_cmd.chanlist = chanlist;
1189 ret = s->do_cmdtest(dev, s, &user_cmd);
1191 /* restore chanlist pointer before copying back */
1192 user_cmd.chanlist = chanlist_saver;
1194 if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1195 DPRINTK("bad cmd address\n");
1196 ret = -EFAULT;
1197 goto cleanup;
1199 cleanup:
1200 kfree(chanlist);
1202 return ret;
1206 COMEDI_LOCK
1207 lock subdevice
1209 arg:
1210 subdevice number
1212 reads:
1213 none
1215 writes:
1216 none
1220 static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1221 void *file)
1223 int ret = 0;
1224 unsigned long flags;
1225 struct comedi_subdevice *s;
1227 if (arg >= dev->n_subdevices)
1228 return -EINVAL;
1229 s = dev->subdevices + arg;
1231 spin_lock_irqsave(&s->spin_lock, flags);
1232 if (s->busy || s->lock)
1233 ret = -EBUSY;
1234 else
1235 s->lock = file;
1236 spin_unlock_irqrestore(&s->spin_lock, flags);
1238 if (ret < 0)
1239 return ret;
1241 #if 0
1242 if (s->lock_f)
1243 ret = s->lock_f(dev, s);
1244 #endif
1246 return ret;
1250 COMEDI_UNLOCK
1251 unlock subdevice
1253 arg:
1254 subdevice number
1256 reads:
1257 none
1259 writes:
1260 none
1262 This function isn't protected by the semaphore, since
1263 we already own the lock.
1265 static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1266 void *file)
1268 struct comedi_subdevice *s;
1270 if (arg >= dev->n_subdevices)
1271 return -EINVAL;
1272 s = dev->subdevices + arg;
1274 if (s->busy)
1275 return -EBUSY;
1277 if (s->lock && s->lock != file)
1278 return -EACCES;
1280 if (s->lock == file) {
1281 #if 0
1282 if (s->unlock)
1283 s->unlock(dev, s);
1284 #endif
1286 s->lock = NULL;
1289 return 0;
1293 COMEDI_CANCEL
1294 cancel acquisition ioctl
1296 arg:
1297 subdevice number
1299 reads:
1300 nothing
1302 writes:
1303 nothing
1306 static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1307 void *file)
1309 struct comedi_subdevice *s;
1311 if (arg >= dev->n_subdevices)
1312 return -EINVAL;
1313 s = dev->subdevices + arg;
1314 if (s->async == NULL)
1315 return -EINVAL;
1317 if (s->lock && s->lock != file)
1318 return -EACCES;
1320 if (!s->busy)
1321 return 0;
1323 if (s->busy != file)
1324 return -EBUSY;
1326 return do_cancel(dev, s);
1330 COMEDI_POLL ioctl
1331 instructs driver to synchronize buffers
1333 arg:
1334 subdevice number
1336 reads:
1337 nothing
1339 writes:
1340 nothing
1343 static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1344 void *file)
1346 struct comedi_subdevice *s;
1348 if (arg >= dev->n_subdevices)
1349 return -EINVAL;
1350 s = dev->subdevices + arg;
1352 if (s->lock && s->lock != file)
1353 return -EACCES;
1355 if (!s->busy)
1356 return 0;
1358 if (s->busy != file)
1359 return -EBUSY;
1361 if (s->poll)
1362 return s->poll(dev, s);
1364 return -EINVAL;
1367 static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1369 int ret = 0;
1371 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1372 ret = s->cancel(dev, s);
1374 do_become_nonbusy(dev, s);
1376 return ret;
1379 void comedi_unmap(struct vm_area_struct *area)
1381 struct comedi_async *async;
1382 struct comedi_device *dev;
1384 async = area->vm_private_data;
1385 dev = async->subdevice->device;
1387 mutex_lock(&dev->mutex);
1388 async->mmap_count--;
1389 mutex_unlock(&dev->mutex);
1392 static struct vm_operations_struct comedi_vm_ops = {
1393 .close = comedi_unmap,
1396 static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1398 const unsigned minor = iminor(file->f_dentry->d_inode);
1399 struct comedi_device_file_info *dev_file_info =
1400 comedi_get_device_file_info(minor);
1401 struct comedi_device *dev = dev_file_info->device;
1402 struct comedi_async *async = NULL;
1403 unsigned long start = vma->vm_start;
1404 unsigned long size;
1405 int n_pages;
1406 int i;
1407 int retval;
1408 struct comedi_subdevice *s;
1410 mutex_lock(&dev->mutex);
1411 if (!dev->attached) {
1412 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1413 retval = -ENODEV;
1414 goto done;
1416 if (vma->vm_flags & VM_WRITE)
1417 s = comedi_get_write_subdevice(dev_file_info);
1418 else
1419 s = comedi_get_read_subdevice(dev_file_info);
1421 if (s == NULL) {
1422 retval = -EINVAL;
1423 goto done;
1425 async = s->async;
1426 if (async == NULL) {
1427 retval = -EINVAL;
1428 goto done;
1431 if (vma->vm_pgoff != 0) {
1432 DPRINTK("comedi: mmap() offset must be 0.\n");
1433 retval = -EINVAL;
1434 goto done;
1437 size = vma->vm_end - vma->vm_start;
1438 if (size > async->prealloc_bufsz) {
1439 retval = -EFAULT;
1440 goto done;
1442 if (size & (~PAGE_MASK)) {
1443 retval = -EFAULT;
1444 goto done;
1447 n_pages = size >> PAGE_SHIFT;
1448 for (i = 0; i < n_pages; ++i) {
1449 if (remap_pfn_range(vma, start,
1450 page_to_pfn(virt_to_page
1451 (async->buf_page_list
1452 [i].virt_addr)), PAGE_SIZE,
1453 PAGE_SHARED)) {
1454 retval = -EAGAIN;
1455 goto done;
1457 start += PAGE_SIZE;
1460 vma->vm_ops = &comedi_vm_ops;
1461 vma->vm_private_data = async;
1463 async->mmap_count++;
1465 retval = 0;
1466 done:
1467 mutex_unlock(&dev->mutex);
1468 return retval;
1471 static unsigned int comedi_poll(struct file *file, poll_table * wait)
1473 unsigned int mask = 0;
1474 const unsigned minor = iminor(file->f_dentry->d_inode);
1475 struct comedi_device_file_info *dev_file_info =
1476 comedi_get_device_file_info(minor);
1477 struct comedi_device *dev = dev_file_info->device;
1478 struct comedi_subdevice *read_subdev;
1479 struct comedi_subdevice *write_subdev;
1481 mutex_lock(&dev->mutex);
1482 if (!dev->attached) {
1483 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1484 mutex_unlock(&dev->mutex);
1485 return 0;
1488 mask = 0;
1489 read_subdev = comedi_get_read_subdevice(dev_file_info);
1490 if (read_subdev) {
1491 poll_wait(file, &read_subdev->async->wait_head, wait);
1492 if (!read_subdev->busy
1493 || comedi_buf_read_n_available(read_subdev->async) > 0
1494 || !(comedi_get_subdevice_runflags(read_subdev) &
1495 SRF_RUNNING)) {
1496 mask |= POLLIN | POLLRDNORM;
1499 write_subdev = comedi_get_write_subdevice(dev_file_info);
1500 if (write_subdev) {
1501 poll_wait(file, &write_subdev->async->wait_head, wait);
1502 comedi_buf_write_alloc(write_subdev->async,
1503 write_subdev->async->prealloc_bufsz);
1504 if (!write_subdev->busy
1505 || !(comedi_get_subdevice_runflags(write_subdev) &
1506 SRF_RUNNING)
1507 || comedi_buf_write_n_allocated(write_subdev->async) >=
1508 bytes_per_sample(write_subdev->async->subdevice)) {
1509 mask |= POLLOUT | POLLWRNORM;
1513 mutex_unlock(&dev->mutex);
1514 return mask;
1517 static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
1518 loff_t * offset)
1520 struct comedi_subdevice *s;
1521 struct comedi_async *async;
1522 int n, m, count = 0, retval = 0;
1523 DECLARE_WAITQUEUE(wait, current);
1524 const unsigned minor = iminor(file->f_dentry->d_inode);
1525 struct comedi_device_file_info *dev_file_info =
1526 comedi_get_device_file_info(minor);
1527 struct comedi_device *dev = dev_file_info->device;
1529 if (!dev->attached) {
1530 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1531 retval = -ENODEV;
1532 goto done;
1535 s = comedi_get_write_subdevice(dev_file_info);
1536 if (s == NULL) {
1537 retval = -EIO;
1538 goto done;
1540 async = s->async;
1542 if (!nbytes) {
1543 retval = 0;
1544 goto done;
1546 if (!s->busy) {
1547 retval = 0;
1548 goto done;
1550 if (s->busy != file) {
1551 retval = -EACCES;
1552 goto done;
1554 add_wait_queue(&async->wait_head, &wait);
1555 while (nbytes > 0 && !retval) {
1556 set_current_state(TASK_INTERRUPTIBLE);
1558 n = nbytes;
1560 m = n;
1561 if (async->buf_write_ptr + m > async->prealloc_bufsz)
1562 m = async->prealloc_bufsz - async->buf_write_ptr;
1563 comedi_buf_write_alloc(async, async->prealloc_bufsz);
1564 if (m > comedi_buf_write_n_allocated(async))
1565 m = comedi_buf_write_n_allocated(async);
1566 if (m < n)
1567 n = m;
1569 if (n == 0) {
1570 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1571 if (comedi_get_subdevice_runflags(s) &
1572 SRF_ERROR) {
1573 retval = -EPIPE;
1574 } else {
1575 retval = 0;
1577 do_become_nonbusy(dev, s);
1578 break;
1580 if (file->f_flags & O_NONBLOCK) {
1581 retval = -EAGAIN;
1582 break;
1584 if (signal_pending(current)) {
1585 retval = -ERESTARTSYS;
1586 break;
1588 schedule();
1589 if (!s->busy)
1590 break;
1591 if (s->busy != file) {
1592 retval = -EACCES;
1593 break;
1595 continue;
1598 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1599 buf, n);
1600 if (m) {
1601 n -= m;
1602 retval = -EFAULT;
1604 comedi_buf_write_free(async, n);
1606 count += n;
1607 nbytes -= n;
1609 buf += n;
1610 break; /* makes device work like a pipe */
1612 set_current_state(TASK_RUNNING);
1613 remove_wait_queue(&async->wait_head, &wait);
1615 done:
1616 return count ? count : retval;
1619 static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
1620 loff_t * offset)
1622 struct comedi_subdevice *s;
1623 struct comedi_async *async;
1624 int n, m, count = 0, retval = 0;
1625 DECLARE_WAITQUEUE(wait, current);
1626 const unsigned minor = iminor(file->f_dentry->d_inode);
1627 struct comedi_device_file_info *dev_file_info =
1628 comedi_get_device_file_info(minor);
1629 struct comedi_device *dev = dev_file_info->device;
1631 if (!dev->attached) {
1632 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1633 retval = -ENODEV;
1634 goto done;
1637 s = comedi_get_read_subdevice(dev_file_info);
1638 if (s == NULL) {
1639 retval = -EIO;
1640 goto done;
1642 async = s->async;
1643 if (!nbytes) {
1644 retval = 0;
1645 goto done;
1647 if (!s->busy) {
1648 retval = 0;
1649 goto done;
1651 if (s->busy != file) {
1652 retval = -EACCES;
1653 goto done;
1656 add_wait_queue(&async->wait_head, &wait);
1657 while (nbytes > 0 && !retval) {
1658 set_current_state(TASK_INTERRUPTIBLE);
1660 n = nbytes;
1662 m = comedi_buf_read_n_available(async);
1663 /* printk("%d available\n",m); */
1664 if (async->buf_read_ptr + m > async->prealloc_bufsz)
1665 m = async->prealloc_bufsz - async->buf_read_ptr;
1666 /* printk("%d contiguous\n",m); */
1667 if (m < n)
1668 n = m;
1670 if (n == 0) {
1671 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1672 do_become_nonbusy(dev, s);
1673 if (comedi_get_subdevice_runflags(s) &
1674 SRF_ERROR) {
1675 retval = -EPIPE;
1676 } else {
1677 retval = 0;
1679 break;
1681 if (file->f_flags & O_NONBLOCK) {
1682 retval = -EAGAIN;
1683 break;
1685 if (signal_pending(current)) {
1686 retval = -ERESTARTSYS;
1687 break;
1689 schedule();
1690 if (!s->busy) {
1691 retval = 0;
1692 break;
1694 if (s->busy != file) {
1695 retval = -EACCES;
1696 break;
1698 continue;
1700 m = copy_to_user(buf, async->prealloc_buf +
1701 async->buf_read_ptr, n);
1702 if (m) {
1703 n -= m;
1704 retval = -EFAULT;
1707 comedi_buf_read_alloc(async, n);
1708 comedi_buf_read_free(async, n);
1710 count += n;
1711 nbytes -= n;
1713 buf += n;
1714 break; /* makes device work like a pipe */
1716 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1717 async->buf_read_count - async->buf_write_count == 0) {
1718 do_become_nonbusy(dev, s);
1720 set_current_state(TASK_RUNNING);
1721 remove_wait_queue(&async->wait_head, &wait);
1723 done:
1724 return count ? count : retval;
1728 This function restores a subdevice to an idle state.
1730 void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1732 struct comedi_async *async = s->async;
1734 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1735 if (async) {
1736 comedi_reset_async_buf(async);
1737 async->inttrig = NULL;
1738 } else {
1739 printk(KERN_ERR
1740 "BUG: (?) do_become_nonbusy called with async=0\n");
1743 s->busy = NULL;
1746 static int comedi_open(struct inode *inode, struct file *file)
1748 const unsigned minor = iminor(inode);
1749 struct comedi_device_file_info *dev_file_info =
1750 comedi_get_device_file_info(minor);
1751 struct comedi_device *dev =
1752 dev_file_info ? dev_file_info->device : NULL;
1754 if (dev == NULL) {
1755 DPRINTK("invalid minor number\n");
1756 return -ENODEV;
1759 /* This is slightly hacky, but we want module autoloading
1760 * to work for root.
1761 * case: user opens device, attached -> ok
1762 * case: user opens device, unattached, in_request_module=0 -> autoload
1763 * case: user opens device, unattached, in_request_module=1 -> fail
1764 * case: root opens device, attached -> ok
1765 * case: root opens device, unattached, in_request_module=1 -> ok
1766 * (typically called from modprobe)
1767 * case: root opens device, unattached, in_request_module=0 -> autoload
1769 * The last could be changed to "-> ok", which would deny root
1770 * autoloading.
1772 mutex_lock(&dev->mutex);
1773 if (dev->attached)
1774 goto ok;
1775 if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1776 DPRINTK("in request module\n");
1777 mutex_unlock(&dev->mutex);
1778 return -ENODEV;
1780 if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1781 goto ok;
1783 dev->in_request_module = 1;
1785 #ifdef CONFIG_KMOD
1786 mutex_unlock(&dev->mutex);
1787 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1788 mutex_lock(&dev->mutex);
1789 #endif
1791 dev->in_request_module = 0;
1793 if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1794 DPRINTK("not attached and not CAP_NET_ADMIN\n");
1795 mutex_unlock(&dev->mutex);
1796 return -ENODEV;
1799 __module_get(THIS_MODULE);
1801 if (dev->attached) {
1802 if (!try_module_get(dev->driver->module)) {
1803 module_put(THIS_MODULE);
1804 mutex_unlock(&dev->mutex);
1805 return -ENOSYS;
1809 if (dev->attached && dev->use_count == 0 && dev->open)
1810 dev->open(dev);
1812 dev->use_count++;
1814 mutex_unlock(&dev->mutex);
1816 return 0;
1819 static int comedi_close(struct inode *inode, struct file *file)
1821 const unsigned minor = iminor(inode);
1822 struct comedi_device_file_info *dev_file_info =
1823 comedi_get_device_file_info(minor);
1824 struct comedi_device *dev = dev_file_info->device;
1825 struct comedi_subdevice *s = NULL;
1826 int i;
1828 mutex_lock(&dev->mutex);
1830 if (dev->subdevices) {
1831 for (i = 0; i < dev->n_subdevices; i++) {
1832 s = dev->subdevices + i;
1834 if (s->busy == file)
1835 do_cancel(dev, s);
1836 if (s->lock == file)
1837 s->lock = NULL;
1840 if (dev->attached && dev->use_count == 1 && dev->close)
1841 dev->close(dev);
1843 module_put(THIS_MODULE);
1844 if (dev->attached)
1845 module_put(dev->driver->module);
1847 dev->use_count--;
1849 mutex_unlock(&dev->mutex);
1851 if (file->f_flags & FASYNC)
1852 comedi_fasync(-1, file, 0);
1854 return 0;
1857 static int comedi_fasync(int fd, struct file *file, int on)
1859 const unsigned minor = iminor(file->f_dentry->d_inode);
1860 struct comedi_device_file_info *dev_file_info =
1861 comedi_get_device_file_info(minor);
1863 struct comedi_device *dev = dev_file_info->device;
1865 return fasync_helper(fd, file, on, &dev->async_queue);
1868 const struct file_operations comedi_fops = {
1869 .owner = THIS_MODULE,
1870 #ifdef HAVE_UNLOCKED_IOCTL
1871 .unlocked_ioctl = comedi_unlocked_ioctl,
1872 #else
1873 .ioctl = comedi_ioctl,
1874 #endif
1875 #ifdef HAVE_COMPAT_IOCTL
1876 .compat_ioctl = comedi_compat_ioctl,
1877 #endif
1878 .open = comedi_open,
1879 .release = comedi_close,
1880 .read = comedi_read,
1881 .write = comedi_write,
1882 .mmap = comedi_mmap,
1883 .poll = comedi_poll,
1884 .fasync = comedi_fasync,
1887 struct class *comedi_class;
1888 static struct cdev comedi_cdev;
1890 static void comedi_cleanup_legacy_minors(void)
1892 unsigned i;
1894 for (i = 0; i < comedi_num_legacy_minors; i++)
1895 comedi_free_board_minor(i);
1898 static int __init comedi_init(void)
1900 int i;
1901 int retval;
1903 printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1904 " - http://www.comedi.org\n");
1906 if (comedi_num_legacy_minors < 0 ||
1907 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1908 printk(KERN_ERR "comedi: error: invalid value for module "
1909 "parameter \"comedi_num_legacy_minors\". Valid values "
1910 "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1911 return -EINVAL;
1915 * comedi is unusable if both comedi_autoconfig and
1916 * comedi_num_legacy_minors are zero, so we might as well adjust the
1917 * defaults in that case
1919 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1920 comedi_num_legacy_minors = 16;
1922 memset(comedi_file_info_table, 0,
1923 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1925 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1926 COMEDI_NUM_MINORS, "comedi");
1927 if (retval)
1928 return -EIO;
1929 cdev_init(&comedi_cdev, &comedi_fops);
1930 comedi_cdev.owner = THIS_MODULE;
1931 kobject_set_name(&comedi_cdev.kobj, "comedi");
1932 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1933 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1934 COMEDI_NUM_MINORS);
1935 return -EIO;
1937 comedi_class = class_create(THIS_MODULE, "comedi");
1938 if (IS_ERR(comedi_class)) {
1939 printk("comedi: failed to create class");
1940 cdev_del(&comedi_cdev);
1941 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1942 COMEDI_NUM_MINORS);
1943 return PTR_ERR(comedi_class);
1946 /* XXX requires /proc interface */
1947 comedi_proc_init();
1949 /* create devices files for legacy/manual use */
1950 for (i = 0; i < comedi_num_legacy_minors; i++) {
1951 int minor;
1952 minor = comedi_alloc_board_minor(NULL);
1953 if (minor < 0) {
1954 comedi_cleanup_legacy_minors();
1955 cdev_del(&comedi_cdev);
1956 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1957 COMEDI_NUM_MINORS);
1958 return minor;
1962 comedi_register_ioctl32();
1964 return 0;
1967 static void __exit comedi_cleanup(void)
1969 int i;
1971 comedi_cleanup_legacy_minors();
1972 for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1973 BUG_ON(comedi_file_info_table[i]);
1975 class_destroy(comedi_class);
1976 cdev_del(&comedi_cdev);
1977 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1979 comedi_proc_cleanup();
1981 comedi_unregister_ioctl32();
1984 module_init(comedi_init);
1985 module_exit(comedi_cleanup);
1987 void comedi_error(const struct comedi_device *dev, const char *s)
1989 printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name, s);
1992 void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
1994 struct comedi_async *async = s->async;
1995 unsigned runflags = 0;
1996 unsigned runflags_mask = 0;
1998 /* DPRINTK("comedi_event 0x%x\n",mask); */
2000 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2001 return;
2003 if (s->
2004 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2005 COMEDI_CB_OVERFLOW)) {
2006 runflags_mask |= SRF_RUNNING;
2008 /* remember if an error event has occured, so an error
2009 * can be returned the next time the user does a read() */
2010 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2011 runflags_mask |= SRF_ERROR;
2012 runflags |= SRF_ERROR;
2014 if (runflags_mask) {
2015 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2016 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2019 if (async->cb_mask & s->async->events) {
2020 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2021 wake_up_interruptible(&async->wait_head);
2022 if (s->subdev_flags & SDF_CMD_READ) {
2023 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2025 if (s->subdev_flags & SDF_CMD_WRITE) {
2026 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2028 } else {
2029 if (async->cb_func)
2030 async->cb_func(s->async->events, async->cb_arg);
2033 s->async->events = 0;
2036 void comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
2037 unsigned bits)
2039 unsigned long flags;
2041 spin_lock_irqsave(&s->spin_lock, flags);
2042 s->runflags &= ~mask;
2043 s->runflags |= (bits & mask);
2044 spin_unlock_irqrestore(&s->spin_lock, flags);
2047 unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2049 unsigned long flags;
2050 unsigned runflags;
2052 spin_lock_irqsave(&s->spin_lock, flags);
2053 runflags = s->runflags;
2054 spin_unlock_irqrestore(&s->spin_lock, flags);
2055 return runflags;
2058 static int is_device_busy(struct comedi_device *dev)
2060 struct comedi_subdevice *s;
2061 int i;
2063 if (!dev->attached)
2064 return 0;
2066 for (i = 0; i < dev->n_subdevices; i++) {
2067 s = dev->subdevices + i;
2068 if (s->busy)
2069 return 1;
2070 if (s->async && s->async->mmap_count)
2071 return 1;
2074 return 0;
2077 void comedi_device_init(struct comedi_device *dev)
2079 memset(dev, 0, sizeof(struct comedi_device));
2080 spin_lock_init(&dev->spinlock);
2081 mutex_init(&dev->mutex);
2082 dev->minor = -1;
2085 void comedi_device_cleanup(struct comedi_device *dev)
2087 if (dev == NULL)
2088 return;
2089 mutex_lock(&dev->mutex);
2090 comedi_device_detach(dev);
2091 mutex_unlock(&dev->mutex);
2092 mutex_destroy(&dev->mutex);
2095 int comedi_alloc_board_minor(struct device *hardware_device)
2097 unsigned long flags;
2098 struct comedi_device_file_info *info;
2099 struct device *csdev;
2100 unsigned i;
2101 int retval;
2103 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2104 if (info == NULL)
2105 return -ENOMEM;
2106 info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2107 if (info->device == NULL) {
2108 kfree(info);
2109 return -ENOMEM;
2111 comedi_device_init(info->device);
2112 spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2113 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2114 if (comedi_file_info_table[i] == NULL) {
2115 comedi_file_info_table[i] = info;
2116 break;
2119 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2120 if (i == COMEDI_NUM_BOARD_MINORS) {
2121 comedi_device_cleanup(info->device);
2122 kfree(info->device);
2123 kfree(info);
2124 printk(KERN_ERR
2125 "comedi: error: ran out of minor numbers for board device files.\n");
2126 return -EBUSY;
2128 info->device->minor = i;
2129 csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2130 MKDEV(COMEDI_MAJOR, i), NULL,
2131 hardware_device, "comedi%i", i);
2132 if (!IS_ERR(csdev))
2133 info->device->class_dev = csdev;
2134 dev_set_drvdata(csdev, info);
2135 retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2136 if (retval) {
2137 printk(KERN_ERR
2138 "comedi: failed to create sysfs attribute file \"%s\".\n",
2139 dev_attr_max_read_buffer_kb.attr.name);
2140 comedi_free_board_minor(i);
2141 return retval;
2143 retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2144 if (retval) {
2145 printk(KERN_ERR
2146 "comedi: failed to create sysfs attribute file \"%s\".\n",
2147 dev_attr_read_buffer_kb.attr.name);
2148 comedi_free_board_minor(i);
2149 return retval;
2151 retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2152 if (retval) {
2153 printk(KERN_ERR
2154 "comedi: failed to create sysfs attribute file \"%s\".\n",
2155 dev_attr_max_write_buffer_kb.attr.name);
2156 comedi_free_board_minor(i);
2157 return retval;
2159 retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2160 if (retval) {
2161 printk(KERN_ERR
2162 "comedi: failed to create sysfs attribute file \"%s\".\n",
2163 dev_attr_write_buffer_kb.attr.name);
2164 comedi_free_board_minor(i);
2165 return retval;
2167 return i;
2170 void comedi_free_board_minor(unsigned minor)
2172 unsigned long flags;
2173 struct comedi_device_file_info *info;
2175 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2176 spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2177 info = comedi_file_info_table[minor];
2178 comedi_file_info_table[minor] = NULL;
2179 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2181 if (info) {
2182 struct comedi_device *dev = info->device;
2183 if (dev) {
2184 if (dev->class_dev) {
2185 device_destroy(comedi_class,
2186 MKDEV(COMEDI_MAJOR, dev->minor));
2188 comedi_device_cleanup(dev);
2189 kfree(dev);
2191 kfree(info);
2195 int comedi_alloc_subdevice_minor(struct comedi_device *dev,
2196 struct comedi_subdevice *s)
2198 unsigned long flags;
2199 struct comedi_device_file_info *info;
2200 struct device *csdev;
2201 unsigned i;
2202 int retval;
2204 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2205 if (info == NULL)
2206 return -ENOMEM;
2207 info->device = dev;
2208 info->read_subdevice = s;
2209 info->write_subdevice = s;
2210 spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2211 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2212 if (comedi_file_info_table[i] == NULL) {
2213 comedi_file_info_table[i] = info;
2214 break;
2217 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2218 if (i == COMEDI_NUM_MINORS) {
2219 kfree(info);
2220 printk(KERN_ERR
2221 "comedi: error: ran out of minor numbers for board device files.\n");
2222 return -EBUSY;
2224 s->minor = i;
2225 csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2226 MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2227 "comedi%i_subd%i", dev->minor,
2228 (int)(s - dev->subdevices));
2229 if (!IS_ERR(csdev))
2230 s->class_dev = csdev;
2231 dev_set_drvdata(csdev, info);
2232 retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2233 if (retval) {
2234 printk(KERN_ERR
2235 "comedi: failed to create sysfs attribute file \"%s\".\n",
2236 dev_attr_max_read_buffer_kb.attr.name);
2237 comedi_free_subdevice_minor(s);
2238 return retval;
2240 retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2241 if (retval) {
2242 printk(KERN_ERR
2243 "comedi: failed to create sysfs attribute file \"%s\".\n",
2244 dev_attr_read_buffer_kb.attr.name);
2245 comedi_free_subdevice_minor(s);
2246 return retval;
2248 retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2249 if (retval) {
2250 printk(KERN_ERR
2251 "comedi: failed to create sysfs attribute file \"%s\".\n",
2252 dev_attr_max_write_buffer_kb.attr.name);
2253 comedi_free_subdevice_minor(s);
2254 return retval;
2256 retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2257 if (retval) {
2258 printk(KERN_ERR
2259 "comedi: failed to create sysfs attribute file \"%s\".\n",
2260 dev_attr_write_buffer_kb.attr.name);
2261 comedi_free_subdevice_minor(s);
2262 return retval;
2264 return i;
2267 void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2269 unsigned long flags;
2270 struct comedi_device_file_info *info;
2272 if (s == NULL)
2273 return;
2274 if (s->minor < 0)
2275 return;
2277 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2278 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2280 spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2281 info = comedi_file_info_table[s->minor];
2282 comedi_file_info_table[s->minor] = NULL;
2283 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2285 if (s->class_dev) {
2286 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2287 s->class_dev = NULL;
2289 kfree(info);
2292 struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2294 unsigned long flags;
2295 struct comedi_device_file_info *info;
2297 BUG_ON(minor >= COMEDI_NUM_MINORS);
2298 spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2299 info = comedi_file_info_table[minor];
2300 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2301 return info;
2304 static int resize_async_buffer(struct comedi_device *dev,
2305 struct comedi_subdevice *s,
2306 struct comedi_async *async, unsigned new_size)
2308 int retval;
2310 if (new_size > async->max_bufsize)
2311 return -EPERM;
2313 if (s->busy) {
2314 DPRINTK("subdevice is busy, cannot resize buffer\n");
2315 return -EBUSY;
2317 if (async->mmap_count) {
2318 DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2319 return -EBUSY;
2322 if (!async->prealloc_buf)
2323 return -EINVAL;
2325 /* make sure buffer is an integral number of pages
2326 * (we round up) */
2327 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2329 retval = comedi_buf_alloc(dev, s, new_size);
2330 if (retval < 0)
2331 return retval;
2333 if (s->buf_change) {
2334 retval = s->buf_change(dev, s, new_size);
2335 if (retval < 0)
2336 return retval;
2339 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2340 dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2341 return 0;
2344 /* sysfs attribute files */
2346 static const unsigned bytes_per_kibi = 1024;
2348 static ssize_t show_max_read_buffer_kb(struct device *dev,
2349 struct device_attribute *attr, char *buf)
2351 ssize_t retval;
2352 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2353 unsigned max_buffer_size_kb = 0;
2354 struct comedi_subdevice *const read_subdevice =
2355 comedi_get_read_subdevice(info);
2357 mutex_lock(&info->device->mutex);
2358 if (read_subdevice &&
2359 (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2360 read_subdevice->async) {
2361 max_buffer_size_kb = read_subdevice->async->max_bufsize /
2362 bytes_per_kibi;
2364 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2365 mutex_unlock(&info->device->mutex);
2367 return retval;
2370 static ssize_t store_max_read_buffer_kb(struct device *dev,
2371 struct device_attribute *attr,
2372 const char *buf, size_t count)
2374 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2375 unsigned long new_max_size_kb;
2376 uint64_t new_max_size;
2377 struct comedi_subdevice *const read_subdevice =
2378 comedi_get_read_subdevice(info);
2380 if (strict_strtoul(buf, 10, &new_max_size_kb))
2381 return -EINVAL;
2382 if (new_max_size_kb != (uint32_t) new_max_size_kb)
2383 return -EINVAL;
2384 new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
2385 if (new_max_size != (uint32_t) new_max_size)
2386 return -EINVAL;
2388 mutex_lock(&info->device->mutex);
2389 if (read_subdevice == NULL ||
2390 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2391 read_subdevice->async == NULL) {
2392 mutex_unlock(&info->device->mutex);
2393 return -EINVAL;
2395 read_subdevice->async->max_bufsize = new_max_size;
2396 mutex_unlock(&info->device->mutex);
2398 return count;
2401 static struct device_attribute dev_attr_max_read_buffer_kb = {
2402 .attr = {
2403 .name = "max_read_buffer_kb",
2404 .mode = S_IRUGO | S_IWUSR},
2405 .show = &show_max_read_buffer_kb,
2406 .store = &store_max_read_buffer_kb
2409 static ssize_t show_read_buffer_kb(struct device *dev,
2410 struct device_attribute *attr, char *buf)
2412 ssize_t retval;
2413 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2414 unsigned buffer_size_kb = 0;
2415 struct comedi_subdevice *const read_subdevice =
2416 comedi_get_read_subdevice(info);
2418 mutex_lock(&info->device->mutex);
2419 if (read_subdevice &&
2420 (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2421 read_subdevice->async) {
2422 buffer_size_kb = read_subdevice->async->prealloc_bufsz /
2423 bytes_per_kibi;
2425 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2426 mutex_unlock(&info->device->mutex);
2428 return retval;
2431 static ssize_t store_read_buffer_kb(struct device *dev,
2432 struct device_attribute *attr,
2433 const char *buf, size_t count)
2435 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2436 unsigned long new_size_kb;
2437 uint64_t new_size;
2438 int retval;
2439 struct comedi_subdevice *const read_subdevice =
2440 comedi_get_read_subdevice(info);
2442 if (strict_strtoul(buf, 10, &new_size_kb))
2443 return -EINVAL;
2444 if (new_size_kb != (uint32_t) new_size_kb)
2445 return -EINVAL;
2446 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2447 if (new_size != (uint32_t) new_size)
2448 return -EINVAL;
2450 mutex_lock(&info->device->mutex);
2451 if (read_subdevice == NULL ||
2452 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2453 read_subdevice->async == NULL) {
2454 mutex_unlock(&info->device->mutex);
2455 return -EINVAL;
2457 retval = resize_async_buffer(info->device, read_subdevice,
2458 read_subdevice->async, new_size);
2459 mutex_unlock(&info->device->mutex);
2461 if (retval < 0)
2462 return retval;
2463 return count;
2466 static struct device_attribute dev_attr_read_buffer_kb = {
2467 .attr = {
2468 .name = "read_buffer_kb",
2469 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2470 .show = &show_read_buffer_kb,
2471 .store = &store_read_buffer_kb
2474 static ssize_t show_max_write_buffer_kb(struct device *dev,
2475 struct device_attribute *attr,
2476 char *buf)
2478 ssize_t retval;
2479 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2480 unsigned max_buffer_size_kb = 0;
2481 struct comedi_subdevice *const write_subdevice =
2482 comedi_get_write_subdevice(info);
2484 mutex_lock(&info->device->mutex);
2485 if (write_subdevice &&
2486 (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2487 write_subdevice->async) {
2488 max_buffer_size_kb = write_subdevice->async->max_bufsize /
2489 bytes_per_kibi;
2491 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2492 mutex_unlock(&info->device->mutex);
2494 return retval;
2497 static ssize_t store_max_write_buffer_kb(struct device *dev,
2498 struct device_attribute *attr,
2499 const char *buf, size_t count)
2501 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2502 unsigned long new_max_size_kb;
2503 uint64_t new_max_size;
2504 struct comedi_subdevice *const write_subdevice =
2505 comedi_get_write_subdevice(info);
2507 if (strict_strtoul(buf, 10, &new_max_size_kb))
2508 return -EINVAL;
2509 if (new_max_size_kb != (uint32_t) new_max_size_kb)
2510 return -EINVAL;
2511 new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
2512 if (new_max_size != (uint32_t) new_max_size)
2513 return -EINVAL;
2515 mutex_lock(&info->device->mutex);
2516 if (write_subdevice == NULL ||
2517 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2518 write_subdevice->async == NULL) {
2519 mutex_unlock(&info->device->mutex);
2520 return -EINVAL;
2522 write_subdevice->async->max_bufsize = new_max_size;
2523 mutex_unlock(&info->device->mutex);
2525 return count;
2528 static struct device_attribute dev_attr_max_write_buffer_kb = {
2529 .attr = {
2530 .name = "max_write_buffer_kb",
2531 .mode = S_IRUGO | S_IWUSR},
2532 .show = &show_max_write_buffer_kb,
2533 .store = &store_max_write_buffer_kb
2536 static ssize_t show_write_buffer_kb(struct device *dev,
2537 struct device_attribute *attr, char *buf)
2539 ssize_t retval;
2540 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2541 unsigned buffer_size_kb = 0;
2542 struct comedi_subdevice *const write_subdevice =
2543 comedi_get_write_subdevice(info);
2545 mutex_lock(&info->device->mutex);
2546 if (write_subdevice &&
2547 (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2548 write_subdevice->async) {
2549 buffer_size_kb = write_subdevice->async->prealloc_bufsz /
2550 bytes_per_kibi;
2552 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2553 mutex_unlock(&info->device->mutex);
2555 return retval;
2558 static ssize_t store_write_buffer_kb(struct device *dev,
2559 struct device_attribute *attr,
2560 const char *buf, size_t count)
2562 struct comedi_device_file_info *info = dev_get_drvdata(dev);
2563 unsigned long new_size_kb;
2564 uint64_t new_size;
2565 int retval;
2566 struct comedi_subdevice *const write_subdevice =
2567 comedi_get_write_subdevice(info);
2569 if (strict_strtoul(buf, 10, &new_size_kb))
2570 return -EINVAL;
2571 if (new_size_kb != (uint32_t) new_size_kb)
2572 return -EINVAL;
2573 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2574 if (new_size != (uint32_t) new_size)
2575 return -EINVAL;
2577 mutex_lock(&info->device->mutex);
2578 if (write_subdevice == NULL ||
2579 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2580 write_subdevice->async == NULL) {
2581 mutex_unlock(&info->device->mutex);
2582 return -EINVAL;
2584 retval = resize_async_buffer(info->device, write_subdevice,
2585 write_subdevice->async, new_size);
2586 mutex_unlock(&info->device->mutex);
2588 if (retval < 0)
2589 return retval;
2590 return count;
2593 static struct device_attribute dev_attr_write_buffer_kb = {
2594 .attr = {
2595 .name = "write_buffer_kb",
2596 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2597 .show = &show_write_buffer_kb,
2598 .store = &store_write_buffer_kb