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