comedi_fops.c revision 21fe2eea6381845956322e63e441f351774de7f9
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		goto copyback;
588	}
589
590	if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
591		bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
592		comedi_buf_read_free(async, bi.bytes_read);
593
594		if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
595							  SRF_RUNNING))
596		    && async->buf_write_count == async->buf_read_count) {
597			do_become_nonbusy(dev, s);
598		}
599	}
600
601	if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
602		bi.bytes_written =
603		    comedi_buf_write_alloc(async, bi.bytes_written);
604		comedi_buf_write_free(async, bi.bytes_written);
605	}
606
607	bi.buf_write_count = async->buf_write_count;
608	bi.buf_write_ptr = async->buf_write_ptr;
609	bi.buf_read_count = async->buf_read_count;
610	bi.buf_read_ptr = async->buf_read_ptr;
611
612copyback:
613	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
614		return -EFAULT;
615
616	return 0;
617}
618
619static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
620		      unsigned int *data, void *file);
621/*
622 *	COMEDI_INSNLIST
623 *	synchronous instructions
624 *
625 *	arg:
626 *		pointer to sync cmd structure
627 *
628 *	reads:
629 *		sync cmd struct at arg
630 *		instruction list
631 *		data (for writes)
632 *
633 *	writes:
634 *		data (for reads)
635 */
636/* arbitrary limits */
637#define MAX_SAMPLES 256
638static int do_insnlist_ioctl(struct comedi_device *dev,
639			     struct comedi_insnlist __user *arg, void *file)
640{
641	struct comedi_insnlist insnlist;
642	struct comedi_insn *insns = NULL;
643	unsigned int *data = NULL;
644	int i = 0;
645	int ret = 0;
646
647	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
648		return -EFAULT;
649
650	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
651	if (!data) {
652		DPRINTK("kmalloc failed\n");
653		ret = -ENOMEM;
654		goto error;
655	}
656
657	insns =
658	    kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
659	if (!insns) {
660		DPRINTK("kmalloc failed\n");
661		ret = -ENOMEM;
662		goto error;
663	}
664
665	if (copy_from_user(insns, insnlist.insns,
666			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
667		DPRINTK("copy_from_user failed\n");
668		ret = -EFAULT;
669		goto error;
670	}
671
672	for (i = 0; i < insnlist.n_insns; i++) {
673		if (insns[i].n > MAX_SAMPLES) {
674			DPRINTK("number of samples too large\n");
675			ret = -EINVAL;
676			goto error;
677		}
678		if (insns[i].insn & INSN_MASK_WRITE) {
679			if (copy_from_user(data, insns[i].data,
680					   insns[i].n * sizeof(unsigned int))) {
681				DPRINTK("copy_from_user failed\n");
682				ret = -EFAULT;
683				goto error;
684			}
685		}
686		ret = parse_insn(dev, insns + i, data, file);
687		if (ret < 0)
688			goto error;
689		if (insns[i].insn & INSN_MASK_READ) {
690			if (copy_to_user(insns[i].data, data,
691					 insns[i].n * sizeof(unsigned int))) {
692				DPRINTK("copy_to_user failed\n");
693				ret = -EFAULT;
694				goto error;
695			}
696		}
697		if (need_resched())
698			schedule();
699	}
700
701error:
702	kfree(insns);
703	kfree(data);
704
705	if (ret < 0)
706		return ret;
707	return i;
708}
709
710static int check_insn_config_length(struct comedi_insn *insn,
711				    unsigned int *data)
712{
713	if (insn->n < 1)
714		return -EINVAL;
715
716	switch (data[0]) {
717	case INSN_CONFIG_DIO_OUTPUT:
718	case INSN_CONFIG_DIO_INPUT:
719	case INSN_CONFIG_DISARM:
720	case INSN_CONFIG_RESET:
721		if (insn->n == 1)
722			return 0;
723		break;
724	case INSN_CONFIG_ARM:
725	case INSN_CONFIG_DIO_QUERY:
726	case INSN_CONFIG_BLOCK_SIZE:
727	case INSN_CONFIG_FILTER:
728	case INSN_CONFIG_SERIAL_CLOCK:
729	case INSN_CONFIG_BIDIRECTIONAL_DATA:
730	case INSN_CONFIG_ALT_SOURCE:
731	case INSN_CONFIG_SET_COUNTER_MODE:
732	case INSN_CONFIG_8254_READ_STATUS:
733	case INSN_CONFIG_SET_ROUTING:
734	case INSN_CONFIG_GET_ROUTING:
735	case INSN_CONFIG_GET_PWM_STATUS:
736	case INSN_CONFIG_PWM_SET_PERIOD:
737	case INSN_CONFIG_PWM_GET_PERIOD:
738		if (insn->n == 2)
739			return 0;
740		break;
741	case INSN_CONFIG_SET_GATE_SRC:
742	case INSN_CONFIG_GET_GATE_SRC:
743	case INSN_CONFIG_SET_CLOCK_SRC:
744	case INSN_CONFIG_GET_CLOCK_SRC:
745	case INSN_CONFIG_SET_OTHER_SRC:
746	case INSN_CONFIG_GET_COUNTER_STATUS:
747	case INSN_CONFIG_PWM_SET_H_BRIDGE:
748	case INSN_CONFIG_PWM_GET_H_BRIDGE:
749	case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
750		if (insn->n == 3)
751			return 0;
752		break;
753	case INSN_CONFIG_PWM_OUTPUT:
754	case INSN_CONFIG_ANALOG_TRIG:
755		if (insn->n == 5)
756			return 0;
757		break;
758		/* by default we allow the insn since we don't have checks for
759		 * all possible cases yet */
760	default:
761		printk(KERN_WARNING
762		       "comedi: no check for data length of config insn id "
763		       "%i is implemented.\n"
764		       " Add a check to %s in %s.\n"
765		       " Assuming n=%i is correct.\n", data[0], __func__,
766		       __FILE__, insn->n);
767		return 0;
768		break;
769	}
770	return -EINVAL;
771}
772
773static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
774		      unsigned int *data, void *file)
775{
776	struct comedi_subdevice *s;
777	int ret = 0;
778	int i;
779
780	if (insn->insn & INSN_MASK_SPECIAL) {
781		/* a non-subdevice instruction */
782
783		switch (insn->insn) {
784		case INSN_GTOD:
785			{
786				struct timeval tv;
787
788				if (insn->n != 2) {
789					ret = -EINVAL;
790					break;
791				}
792
793				do_gettimeofday(&tv);
794				data[0] = tv.tv_sec;
795				data[1] = tv.tv_usec;
796				ret = 2;
797
798				break;
799			}
800		case INSN_WAIT:
801			if (insn->n != 1 || data[0] >= 100000) {
802				ret = -EINVAL;
803				break;
804			}
805			udelay(data[0] / 1000);
806			ret = 1;
807			break;
808		case INSN_INTTRIG:
809			if (insn->n != 1) {
810				ret = -EINVAL;
811				break;
812			}
813			if (insn->subdev >= dev->n_subdevices) {
814				DPRINTK("%d not usable subdevice\n",
815					insn->subdev);
816				ret = -EINVAL;
817				break;
818			}
819			s = dev->subdevices + insn->subdev;
820			if (!s->async) {
821				DPRINTK("no async\n");
822				ret = -EINVAL;
823				break;
824			}
825			if (!s->async->inttrig) {
826				DPRINTK("no inttrig\n");
827				ret = -EAGAIN;
828				break;
829			}
830			ret = s->async->inttrig(dev, s, insn->data[0]);
831			if (ret >= 0)
832				ret = 1;
833			break;
834		default:
835			DPRINTK("invalid insn\n");
836			ret = -EINVAL;
837			break;
838		}
839	} else {
840		/* a subdevice instruction */
841		unsigned int maxdata;
842
843		if (insn->subdev >= dev->n_subdevices) {
844			DPRINTK("subdevice %d out of range\n", insn->subdev);
845			ret = -EINVAL;
846			goto out;
847		}
848		s = dev->subdevices + insn->subdev;
849
850		if (s->type == COMEDI_SUBD_UNUSED) {
851			DPRINTK("%d not usable subdevice\n", insn->subdev);
852			ret = -EIO;
853			goto out;
854		}
855
856		/* are we locked? (ioctl lock) */
857		if (s->lock && s->lock != file) {
858			DPRINTK("device locked\n");
859			ret = -EACCES;
860			goto out;
861		}
862
863		ret = comedi_check_chanlist(s, 1, &insn->chanspec);
864		if (ret < 0) {
865			ret = -EINVAL;
866			DPRINTK("bad chanspec\n");
867			goto out;
868		}
869
870		if (s->busy) {
871			ret = -EBUSY;
872			goto out;
873		}
874		/* This looks arbitrary.  It is. */
875		s->busy = &parse_insn;
876		switch (insn->insn) {
877		case INSN_READ:
878			ret = s->insn_read(dev, s, insn, data);
879			break;
880		case INSN_WRITE:
881			maxdata = s->maxdata_list
882			    ? s->maxdata_list[CR_CHAN(insn->chanspec)]
883			    : s->maxdata;
884			for (i = 0; i < insn->n; ++i) {
885				if (data[i] > maxdata) {
886					ret = -EINVAL;
887					DPRINTK("bad data value(s)\n");
888					break;
889				}
890			}
891			if (ret == 0)
892				ret = s->insn_write(dev, s, insn, data);
893			break;
894		case INSN_BITS:
895			if (insn->n != 2) {
896				ret = -EINVAL;
897				break;
898			}
899			ret = s->insn_bits(dev, s, insn, data);
900			break;
901		case INSN_CONFIG:
902			ret = check_insn_config_length(insn, data);
903			if (ret)
904				break;
905			ret = s->insn_config(dev, s, insn, data);
906			break;
907		default:
908			ret = -EINVAL;
909			break;
910		}
911
912		s->busy = NULL;
913	}
914
915out:
916	return ret;
917}
918
919/*
920 *	COMEDI_INSN
921 *	synchronous instructions
922 *
923 *	arg:
924 *		pointer to insn
925 *
926 *	reads:
927 *		struct comedi_insn struct at arg
928 *		data (for writes)
929 *
930 *	writes:
931 *		data (for reads)
932 */
933static int do_insn_ioctl(struct comedi_device *dev,
934			 struct comedi_insn __user *arg, void *file)
935{
936	struct comedi_insn insn;
937	unsigned int *data = NULL;
938	int ret = 0;
939
940	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
941	if (!data) {
942		ret = -ENOMEM;
943		goto error;
944	}
945
946	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
947		ret = -EFAULT;
948		goto error;
949	}
950
951	/* This is where the behavior of insn and insnlist deviate. */
952	if (insn.n > MAX_SAMPLES)
953		insn.n = MAX_SAMPLES;
954	if (insn.insn & INSN_MASK_WRITE) {
955		if (copy_from_user(data,
956				   insn.data,
957				   insn.n * sizeof(unsigned int))) {
958			ret = -EFAULT;
959			goto error;
960		}
961	}
962	ret = parse_insn(dev, &insn, data, file);
963	if (ret < 0)
964		goto error;
965	if (insn.insn & INSN_MASK_READ) {
966		if (copy_to_user(insn.data,
967				 data,
968				 insn.n * sizeof(unsigned int))) {
969			ret = -EFAULT;
970			goto error;
971		}
972	}
973	ret = insn.n;
974
975error:
976	kfree(data);
977
978	return ret;
979}
980
981static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
982					  unsigned mask, unsigned bits)
983{
984	unsigned long flags;
985
986	spin_lock_irqsave(&s->spin_lock, flags);
987	s->runflags &= ~mask;
988	s->runflags |= (bits & mask);
989	spin_unlock_irqrestore(&s->spin_lock, flags);
990}
991
992static int do_cmd_ioctl(struct comedi_device *dev,
993			struct comedi_cmd __user *cmd, void *file)
994{
995	struct comedi_cmd user_cmd;
996	struct comedi_subdevice *s;
997	struct comedi_async *async;
998	int ret = 0;
999	unsigned int __user *chanlist_saver = NULL;
1000
1001	if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
1002		DPRINTK("bad cmd address\n");
1003		return -EFAULT;
1004	}
1005	/* save user's chanlist pointer so it can be restored later */
1006	chanlist_saver = user_cmd.chanlist;
1007
1008	if (user_cmd.subdev >= dev->n_subdevices) {
1009		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1010		return -ENODEV;
1011	}
1012
1013	s = dev->subdevices + user_cmd.subdev;
1014	async = s->async;
1015
1016	if (s->type == COMEDI_SUBD_UNUSED) {
1017		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1018		return -EIO;
1019	}
1020
1021	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1022		DPRINTK("subdevice %i does not support commands\n",
1023			user_cmd.subdev);
1024		return -EIO;
1025	}
1026
1027	/* are we locked? (ioctl lock) */
1028	if (s->lock && s->lock != file) {
1029		DPRINTK("subdevice locked\n");
1030		return -EACCES;
1031	}
1032
1033	/* are we busy? */
1034	if (s->busy) {
1035		DPRINTK("subdevice busy\n");
1036		return -EBUSY;
1037	}
1038	s->busy = file;
1039
1040	/* make sure channel/gain list isn't too long */
1041	if (user_cmd.chanlist_len > s->len_chanlist) {
1042		DPRINTK("channel/gain list too long %u > %d\n",
1043			user_cmd.chanlist_len, s->len_chanlist);
1044		ret = -EINVAL;
1045		goto cleanup;
1046	}
1047
1048	/* make sure channel/gain list isn't too short */
1049	if (user_cmd.chanlist_len < 1) {
1050		DPRINTK("channel/gain list too short %u < 1\n",
1051			user_cmd.chanlist_len);
1052		ret = -EINVAL;
1053		goto cleanup;
1054	}
1055
1056	kfree(async->cmd.chanlist);
1057	async->cmd = user_cmd;
1058	async->cmd.data = NULL;
1059	/* load channel/gain list */
1060	async->cmd.chanlist =
1061	    kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1062	if (!async->cmd.chanlist) {
1063		DPRINTK("allocation failed\n");
1064		ret = -ENOMEM;
1065		goto cleanup;
1066	}
1067
1068	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
1069			   async->cmd.chanlist_len * sizeof(int))) {
1070		DPRINTK("fault reading chanlist\n");
1071		ret = -EFAULT;
1072		goto cleanup;
1073	}
1074
1075	/* make sure each element in channel/gain list is valid */
1076	ret = comedi_check_chanlist(s,
1077				    async->cmd.chanlist_len,
1078				    async->cmd.chanlist);
1079	if (ret < 0) {
1080		DPRINTK("bad chanlist\n");
1081		goto cleanup;
1082	}
1083
1084	ret = s->do_cmdtest(dev, s, &async->cmd);
1085
1086	if (async->cmd.flags & TRIG_BOGUS || ret) {
1087		DPRINTK("test returned %d\n", ret);
1088		user_cmd = async->cmd;
1089		/* restore chanlist pointer before copying back */
1090		user_cmd.chanlist = chanlist_saver;
1091		user_cmd.data = NULL;
1092		if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
1093			DPRINTK("fault writing cmd\n");
1094			ret = -EFAULT;
1095			goto cleanup;
1096		}
1097		ret = -EAGAIN;
1098		goto cleanup;
1099	}
1100
1101	if (!async->prealloc_bufsz) {
1102		ret = -ENOMEM;
1103		DPRINTK("no buffer (?)\n");
1104		goto cleanup;
1105	}
1106
1107	comedi_reset_async_buf(async);
1108
1109	async->cb_mask =
1110	    COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1111	    COMEDI_CB_OVERFLOW;
1112	if (async->cmd.flags & TRIG_WAKE_EOS)
1113		async->cb_mask |= COMEDI_CB_EOS;
1114
1115	comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1116
1117	ret = s->do_cmd(dev, s);
1118	if (ret == 0)
1119		return 0;
1120
1121cleanup:
1122	do_become_nonbusy(dev, s);
1123
1124	return ret;
1125}
1126
1127/*
1128	COMEDI_CMDTEST
1129	command testing ioctl
1130
1131	arg:
1132		pointer to cmd structure
1133
1134	reads:
1135		cmd structure at arg
1136		channel/range list
1137
1138	writes:
1139		modified cmd structure at arg
1140
1141*/
1142static int do_cmdtest_ioctl(struct comedi_device *dev,
1143			    struct comedi_cmd __user *arg, void *file)
1144{
1145	struct comedi_cmd user_cmd;
1146	struct comedi_subdevice *s;
1147	int ret = 0;
1148	unsigned int *chanlist = NULL;
1149	unsigned int __user *chanlist_saver = NULL;
1150
1151	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
1152		DPRINTK("bad cmd address\n");
1153		return -EFAULT;
1154	}
1155	/* save user's chanlist pointer so it can be restored later */
1156	chanlist_saver = user_cmd.chanlist;
1157
1158	if (user_cmd.subdev >= dev->n_subdevices) {
1159		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1160		return -ENODEV;
1161	}
1162
1163	s = dev->subdevices + user_cmd.subdev;
1164	if (s->type == COMEDI_SUBD_UNUSED) {
1165		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1166		return -EIO;
1167	}
1168
1169	if (!s->do_cmd || !s->do_cmdtest) {
1170		DPRINTK("subdevice %i does not support commands\n",
1171			user_cmd.subdev);
1172		return -EIO;
1173	}
1174
1175	/* make sure channel/gain list isn't too long */
1176	if (user_cmd.chanlist_len > s->len_chanlist) {
1177		DPRINTK("channel/gain list too long %d > %d\n",
1178			user_cmd.chanlist_len, s->len_chanlist);
1179		ret = -EINVAL;
1180		goto cleanup;
1181	}
1182
1183	/* load channel/gain list */
1184	if (user_cmd.chanlist) {
1185		chanlist =
1186		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1187		if (!chanlist) {
1188			DPRINTK("allocation failed\n");
1189			ret = -ENOMEM;
1190			goto cleanup;
1191		}
1192
1193		if (copy_from_user(chanlist, user_cmd.chanlist,
1194				   user_cmd.chanlist_len * sizeof(int))) {
1195			DPRINTK("fault reading chanlist\n");
1196			ret = -EFAULT;
1197			goto cleanup;
1198		}
1199
1200		/* make sure each element in channel/gain list is valid */
1201		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
1202		if (ret < 0) {
1203			DPRINTK("bad chanlist\n");
1204			goto cleanup;
1205		}
1206
1207		user_cmd.chanlist = chanlist;
1208	}
1209
1210	ret = s->do_cmdtest(dev, s, &user_cmd);
1211
1212	/* restore chanlist pointer before copying back */
1213	user_cmd.chanlist = chanlist_saver;
1214
1215	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
1216		DPRINTK("bad cmd address\n");
1217		ret = -EFAULT;
1218		goto cleanup;
1219	}
1220cleanup:
1221	kfree(chanlist);
1222
1223	return ret;
1224}
1225
1226/*
1227	COMEDI_LOCK
1228	lock subdevice
1229
1230	arg:
1231		subdevice number
1232
1233	reads:
1234		none
1235
1236	writes:
1237		none
1238
1239*/
1240
1241static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1242			 void *file)
1243{
1244	int ret = 0;
1245	unsigned long flags;
1246	struct comedi_subdevice *s;
1247
1248	if (arg >= dev->n_subdevices)
1249		return -EINVAL;
1250	s = dev->subdevices + arg;
1251
1252	spin_lock_irqsave(&s->spin_lock, flags);
1253	if (s->busy || s->lock)
1254		ret = -EBUSY;
1255	else
1256		s->lock = file;
1257	spin_unlock_irqrestore(&s->spin_lock, flags);
1258
1259	if (ret < 0)
1260		return ret;
1261
1262#if 0
1263	if (s->lock_f)
1264		ret = s->lock_f(dev, s);
1265#endif
1266
1267	return ret;
1268}
1269
1270/*
1271	COMEDI_UNLOCK
1272	unlock subdevice
1273
1274	arg:
1275		subdevice number
1276
1277	reads:
1278		none
1279
1280	writes:
1281		none
1282
1283	This function isn't protected by the semaphore, since
1284	we already own the lock.
1285*/
1286static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1287			   void *file)
1288{
1289	struct comedi_subdevice *s;
1290
1291	if (arg >= dev->n_subdevices)
1292		return -EINVAL;
1293	s = dev->subdevices + arg;
1294
1295	if (s->busy)
1296		return -EBUSY;
1297
1298	if (s->lock && s->lock != file)
1299		return -EACCES;
1300
1301	if (s->lock == file) {
1302#if 0
1303		if (s->unlock)
1304			s->unlock(dev, s);
1305#endif
1306
1307		s->lock = NULL;
1308	}
1309
1310	return 0;
1311}
1312
1313/*
1314	COMEDI_CANCEL
1315	cancel acquisition ioctl
1316
1317	arg:
1318		subdevice number
1319
1320	reads:
1321		nothing
1322
1323	writes:
1324		nothing
1325
1326*/
1327static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1328			   void *file)
1329{
1330	struct comedi_subdevice *s;
1331
1332	if (arg >= dev->n_subdevices)
1333		return -EINVAL;
1334	s = dev->subdevices + arg;
1335	if (s->async == NULL)
1336		return -EINVAL;
1337
1338	if (s->lock && s->lock != file)
1339		return -EACCES;
1340
1341	if (!s->busy)
1342		return 0;
1343
1344	if (s->busy != file)
1345		return -EBUSY;
1346
1347	return do_cancel(dev, s);
1348}
1349
1350/*
1351	COMEDI_POLL ioctl
1352	instructs driver to synchronize buffers
1353
1354	arg:
1355		subdevice number
1356
1357	reads:
1358		nothing
1359
1360	writes:
1361		nothing
1362
1363*/
1364static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1365			 void *file)
1366{
1367	struct comedi_subdevice *s;
1368
1369	if (arg >= dev->n_subdevices)
1370		return -EINVAL;
1371	s = dev->subdevices + arg;
1372
1373	if (s->lock && s->lock != file)
1374		return -EACCES;
1375
1376	if (!s->busy)
1377		return 0;
1378
1379	if (s->busy != file)
1380		return -EBUSY;
1381
1382	if (s->poll)
1383		return s->poll(dev, s);
1384
1385	return -EINVAL;
1386}
1387
1388static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1389{
1390	int ret = 0;
1391
1392	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1393		ret = s->cancel(dev, s);
1394
1395	do_become_nonbusy(dev, s);
1396
1397	return ret;
1398}
1399
1400static void comedi_unmap(struct vm_area_struct *area)
1401{
1402	struct comedi_async *async;
1403	struct comedi_device *dev;
1404
1405	async = area->vm_private_data;
1406	dev = async->subdevice->device;
1407
1408	mutex_lock(&dev->mutex);
1409	async->mmap_count--;
1410	mutex_unlock(&dev->mutex);
1411}
1412
1413static struct vm_operations_struct comedi_vm_ops = {
1414	.close = comedi_unmap,
1415};
1416
1417static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1418{
1419	const unsigned minor = iminor(file->f_dentry->d_inode);
1420	struct comedi_device_file_info *dev_file_info =
1421	    comedi_get_device_file_info(minor);
1422	struct comedi_device *dev = dev_file_info->device;
1423	struct comedi_async *async = NULL;
1424	unsigned long start = vma->vm_start;
1425	unsigned long size;
1426	int n_pages;
1427	int i;
1428	int retval;
1429	struct comedi_subdevice *s;
1430
1431	mutex_lock(&dev->mutex);
1432	if (!dev->attached) {
1433		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1434		retval = -ENODEV;
1435		goto done;
1436	}
1437	if (vma->vm_flags & VM_WRITE)
1438		s = comedi_get_write_subdevice(dev_file_info);
1439	else
1440		s = comedi_get_read_subdevice(dev_file_info);
1441
1442	if (s == NULL) {
1443		retval = -EINVAL;
1444		goto done;
1445	}
1446	async = s->async;
1447	if (async == NULL) {
1448		retval = -EINVAL;
1449		goto done;
1450	}
1451
1452	if (vma->vm_pgoff != 0) {
1453		DPRINTK("comedi: mmap() offset must be 0.\n");
1454		retval = -EINVAL;
1455		goto done;
1456	}
1457
1458	size = vma->vm_end - vma->vm_start;
1459	if (size > async->prealloc_bufsz) {
1460		retval = -EFAULT;
1461		goto done;
1462	}
1463	if (size & (~PAGE_MASK)) {
1464		retval = -EFAULT;
1465		goto done;
1466	}
1467
1468	n_pages = size >> PAGE_SHIFT;
1469	for (i = 0; i < n_pages; ++i) {
1470		if (remap_pfn_range(vma, start,
1471				    page_to_pfn(virt_to_page
1472						(async->buf_page_list
1473						 [i].virt_addr)), PAGE_SIZE,
1474				    PAGE_SHARED)) {
1475			retval = -EAGAIN;
1476			goto done;
1477		}
1478		start += PAGE_SIZE;
1479	}
1480
1481	vma->vm_ops = &comedi_vm_ops;
1482	vma->vm_private_data = async;
1483
1484	async->mmap_count++;
1485
1486	retval = 0;
1487done:
1488	mutex_unlock(&dev->mutex);
1489	return retval;
1490}
1491
1492static unsigned int comedi_poll(struct file *file, poll_table * wait)
1493{
1494	unsigned int mask = 0;
1495	const unsigned minor = iminor(file->f_dentry->d_inode);
1496	struct comedi_device_file_info *dev_file_info =
1497	    comedi_get_device_file_info(minor);
1498	struct comedi_device *dev = dev_file_info->device;
1499	struct comedi_subdevice *read_subdev;
1500	struct comedi_subdevice *write_subdev;
1501
1502	mutex_lock(&dev->mutex);
1503	if (!dev->attached) {
1504		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1505		mutex_unlock(&dev->mutex);
1506		return 0;
1507	}
1508
1509	mask = 0;
1510	read_subdev = comedi_get_read_subdevice(dev_file_info);
1511	if (read_subdev) {
1512		poll_wait(file, &read_subdev->async->wait_head, wait);
1513		if (!read_subdev->busy
1514		    || comedi_buf_read_n_available(read_subdev->async) > 0
1515		    || !(comedi_get_subdevice_runflags(read_subdev) &
1516			 SRF_RUNNING)) {
1517			mask |= POLLIN | POLLRDNORM;
1518		}
1519	}
1520	write_subdev = comedi_get_write_subdevice(dev_file_info);
1521	if (write_subdev) {
1522		poll_wait(file, &write_subdev->async->wait_head, wait);
1523		comedi_buf_write_alloc(write_subdev->async,
1524				       write_subdev->async->prealloc_bufsz);
1525		if (!write_subdev->busy
1526		    || !(comedi_get_subdevice_runflags(write_subdev) &
1527			 SRF_RUNNING)
1528		    || comedi_buf_write_n_allocated(write_subdev->async) >=
1529		    bytes_per_sample(write_subdev->async->subdevice)) {
1530			mask |= POLLOUT | POLLWRNORM;
1531		}
1532	}
1533
1534	mutex_unlock(&dev->mutex);
1535	return mask;
1536}
1537
1538static ssize_t comedi_write(struct file *file, const char __user *buf,
1539			    size_t nbytes, loff_t *offset)
1540{
1541	struct comedi_subdevice *s;
1542	struct comedi_async *async;
1543	int n, m, count = 0, retval = 0;
1544	DECLARE_WAITQUEUE(wait, current);
1545	const unsigned minor = iminor(file->f_dentry->d_inode);
1546	struct comedi_device_file_info *dev_file_info =
1547	    comedi_get_device_file_info(minor);
1548	struct comedi_device *dev = dev_file_info->device;
1549
1550	if (!dev->attached) {
1551		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1552		retval = -ENODEV;
1553		goto done;
1554	}
1555
1556	s = comedi_get_write_subdevice(dev_file_info);
1557	if (s == NULL) {
1558		retval = -EIO;
1559		goto done;
1560	}
1561	async = s->async;
1562
1563	if (!nbytes) {
1564		retval = 0;
1565		goto done;
1566	}
1567	if (!s->busy) {
1568		retval = 0;
1569		goto done;
1570	}
1571	if (s->busy != file) {
1572		retval = -EACCES;
1573		goto done;
1574	}
1575	add_wait_queue(&async->wait_head, &wait);
1576	while (nbytes > 0 && !retval) {
1577		set_current_state(TASK_INTERRUPTIBLE);
1578
1579		n = nbytes;
1580
1581		m = n;
1582		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1583			m = async->prealloc_bufsz - async->buf_write_ptr;
1584		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1585		if (m > comedi_buf_write_n_allocated(async))
1586			m = comedi_buf_write_n_allocated(async);
1587		if (m < n)
1588			n = m;
1589
1590		if (n == 0) {
1591			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1592				if (comedi_get_subdevice_runflags(s) &
1593				    SRF_ERROR) {
1594					retval = -EPIPE;
1595				} else {
1596					retval = 0;
1597				}
1598				do_become_nonbusy(dev, s);
1599				break;
1600			}
1601			if (file->f_flags & O_NONBLOCK) {
1602				retval = -EAGAIN;
1603				break;
1604			}
1605			if (signal_pending(current)) {
1606				retval = -ERESTARTSYS;
1607				break;
1608			}
1609			schedule();
1610			if (!s->busy)
1611				break;
1612			if (s->busy != file) {
1613				retval = -EACCES;
1614				break;
1615			}
1616			continue;
1617		}
1618
1619		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1620				   buf, n);
1621		if (m) {
1622			n -= m;
1623			retval = -EFAULT;
1624		}
1625		comedi_buf_write_free(async, n);
1626
1627		count += n;
1628		nbytes -= n;
1629
1630		buf += n;
1631		break;		/* makes device work like a pipe */
1632	}
1633	set_current_state(TASK_RUNNING);
1634	remove_wait_queue(&async->wait_head, &wait);
1635
1636done:
1637	return count ? count : retval;
1638}
1639
1640static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
1641				loff_t *offset)
1642{
1643	struct comedi_subdevice *s;
1644	struct comedi_async *async;
1645	int n, m, count = 0, retval = 0;
1646	DECLARE_WAITQUEUE(wait, current);
1647	const unsigned minor = iminor(file->f_dentry->d_inode);
1648	struct comedi_device_file_info *dev_file_info =
1649	    comedi_get_device_file_info(minor);
1650	struct comedi_device *dev = dev_file_info->device;
1651
1652	if (!dev->attached) {
1653		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1654		retval = -ENODEV;
1655		goto done;
1656	}
1657
1658	s = comedi_get_read_subdevice(dev_file_info);
1659	if (s == NULL) {
1660		retval = -EIO;
1661		goto done;
1662	}
1663	async = s->async;
1664	if (!nbytes) {
1665		retval = 0;
1666		goto done;
1667	}
1668	if (!s->busy) {
1669		retval = 0;
1670		goto done;
1671	}
1672	if (s->busy != file) {
1673		retval = -EACCES;
1674		goto done;
1675	}
1676
1677	add_wait_queue(&async->wait_head, &wait);
1678	while (nbytes > 0 && !retval) {
1679		set_current_state(TASK_INTERRUPTIBLE);
1680
1681		n = nbytes;
1682
1683		m = comedi_buf_read_n_available(async);
1684		/* printk("%d available\n",m); */
1685		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1686			m = async->prealloc_bufsz - async->buf_read_ptr;
1687		/* printk("%d contiguous\n",m); */
1688		if (m < n)
1689			n = m;
1690
1691		if (n == 0) {
1692			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1693				do_become_nonbusy(dev, s);
1694				if (comedi_get_subdevice_runflags(s) &
1695				    SRF_ERROR) {
1696					retval = -EPIPE;
1697				} else {
1698					retval = 0;
1699				}
1700				break;
1701			}
1702			if (file->f_flags & O_NONBLOCK) {
1703				retval = -EAGAIN;
1704				break;
1705			}
1706			if (signal_pending(current)) {
1707				retval = -ERESTARTSYS;
1708				break;
1709			}
1710			schedule();
1711			if (!s->busy) {
1712				retval = 0;
1713				break;
1714			}
1715			if (s->busy != file) {
1716				retval = -EACCES;
1717				break;
1718			}
1719			continue;
1720		}
1721		m = copy_to_user(buf, async->prealloc_buf +
1722				 async->buf_read_ptr, n);
1723		if (m) {
1724			n -= m;
1725			retval = -EFAULT;
1726		}
1727
1728		comedi_buf_read_alloc(async, n);
1729		comedi_buf_read_free(async, n);
1730
1731		count += n;
1732		nbytes -= n;
1733
1734		buf += n;
1735		break;		/* makes device work like a pipe */
1736	}
1737	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1738	    async->buf_read_count - async->buf_write_count == 0) {
1739		do_become_nonbusy(dev, s);
1740	}
1741	set_current_state(TASK_RUNNING);
1742	remove_wait_queue(&async->wait_head, &wait);
1743
1744done:
1745	return count ? count : retval;
1746}
1747
1748/*
1749   This function restores a subdevice to an idle state.
1750 */
1751void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1752{
1753	struct comedi_async *async = s->async;
1754
1755	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1756	if (async) {
1757		comedi_reset_async_buf(async);
1758		async->inttrig = NULL;
1759	} else {
1760		printk(KERN_ERR
1761		       "BUG: (?) do_become_nonbusy called with async=0\n");
1762	}
1763
1764	s->busy = NULL;
1765}
1766
1767static int comedi_open(struct inode *inode, struct file *file)
1768{
1769	const unsigned minor = iminor(inode);
1770	struct comedi_device_file_info *dev_file_info =
1771	    comedi_get_device_file_info(minor);
1772	struct comedi_device *dev =
1773	    dev_file_info ? dev_file_info->device : NULL;
1774
1775	if (dev == NULL) {
1776		DPRINTK("invalid minor number\n");
1777		return -ENODEV;
1778	}
1779
1780	/* This is slightly hacky, but we want module autoloading
1781	 * to work for root.
1782	 * case: user opens device, attached -> ok
1783	 * case: user opens device, unattached, in_request_module=0 -> autoload
1784	 * case: user opens device, unattached, in_request_module=1 -> fail
1785	 * case: root opens device, attached -> ok
1786	 * case: root opens device, unattached, in_request_module=1 -> ok
1787	 *   (typically called from modprobe)
1788	 * case: root opens device, unattached, in_request_module=0 -> autoload
1789	 *
1790	 * The last could be changed to "-> ok", which would deny root
1791	 * autoloading.
1792	 */
1793	mutex_lock(&dev->mutex);
1794	if (dev->attached)
1795		goto ok;
1796	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1797		DPRINTK("in request module\n");
1798		mutex_unlock(&dev->mutex);
1799		return -ENODEV;
1800	}
1801	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1802		goto ok;
1803
1804	dev->in_request_module = 1;
1805
1806#ifdef CONFIG_KMOD
1807	mutex_unlock(&dev->mutex);
1808	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1809	mutex_lock(&dev->mutex);
1810#endif
1811
1812	dev->in_request_module = 0;
1813
1814	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1815		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1816		mutex_unlock(&dev->mutex);
1817		return -ENODEV;
1818	}
1819ok:
1820	__module_get(THIS_MODULE);
1821
1822	if (dev->attached) {
1823		if (!try_module_get(dev->driver->module)) {
1824			module_put(THIS_MODULE);
1825			mutex_unlock(&dev->mutex);
1826			return -ENOSYS;
1827		}
1828	}
1829
1830	if (dev->attached && dev->use_count == 0 && dev->open)
1831		dev->open(dev);
1832
1833	dev->use_count++;
1834
1835	mutex_unlock(&dev->mutex);
1836
1837	return 0;
1838}
1839
1840static int comedi_close(struct inode *inode, struct file *file)
1841{
1842	const unsigned minor = iminor(inode);
1843	struct comedi_device_file_info *dev_file_info =
1844	    comedi_get_device_file_info(minor);
1845	struct comedi_device *dev = dev_file_info->device;
1846	struct comedi_subdevice *s = NULL;
1847	int i;
1848
1849	mutex_lock(&dev->mutex);
1850
1851	if (dev->subdevices) {
1852		for (i = 0; i < dev->n_subdevices; i++) {
1853			s = dev->subdevices + i;
1854
1855			if (s->busy == file)
1856				do_cancel(dev, s);
1857			if (s->lock == file)
1858				s->lock = NULL;
1859		}
1860	}
1861	if (dev->attached && dev->use_count == 1 && dev->close)
1862		dev->close(dev);
1863
1864	module_put(THIS_MODULE);
1865	if (dev->attached)
1866		module_put(dev->driver->module);
1867
1868	dev->use_count--;
1869
1870	mutex_unlock(&dev->mutex);
1871
1872	if (file->f_flags & FASYNC)
1873		comedi_fasync(-1, file, 0);
1874
1875	return 0;
1876}
1877
1878static int comedi_fasync(int fd, struct file *file, int on)
1879{
1880	const unsigned minor = iminor(file->f_dentry->d_inode);
1881	struct comedi_device_file_info *dev_file_info =
1882	    comedi_get_device_file_info(minor);
1883
1884	struct comedi_device *dev = dev_file_info->device;
1885
1886	return fasync_helper(fd, file, on, &dev->async_queue);
1887}
1888
1889const struct file_operations comedi_fops = {
1890	.owner = THIS_MODULE,
1891	.unlocked_ioctl = comedi_unlocked_ioctl,
1892	.compat_ioctl = comedi_compat_ioctl,
1893	.open = comedi_open,
1894	.release = comedi_close,
1895	.read = comedi_read,
1896	.write = comedi_write,
1897	.mmap = comedi_mmap,
1898	.poll = comedi_poll,
1899	.fasync = comedi_fasync,
1900};
1901
1902struct class *comedi_class;
1903static struct cdev comedi_cdev;
1904
1905static void comedi_cleanup_legacy_minors(void)
1906{
1907	unsigned i;
1908
1909	for (i = 0; i < comedi_num_legacy_minors; i++)
1910		comedi_free_board_minor(i);
1911}
1912
1913static int __init comedi_init(void)
1914{
1915	int i;
1916	int retval;
1917
1918	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1919	       " - http://www.comedi.org\n");
1920
1921	if (comedi_num_legacy_minors < 0 ||
1922	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1923		printk(KERN_ERR "comedi: error: invalid value for module "
1924		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1925		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1926		return -EINVAL;
1927	}
1928
1929	/*
1930	 * comedi is unusable if both comedi_autoconfig and
1931	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1932	 * defaults in that case
1933	 */
1934	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1935		comedi_num_legacy_minors = 16;
1936
1937	memset(comedi_file_info_table, 0,
1938	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1939
1940	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1941					COMEDI_NUM_MINORS, "comedi");
1942	if (retval)
1943		return -EIO;
1944	cdev_init(&comedi_cdev, &comedi_fops);
1945	comedi_cdev.owner = THIS_MODULE;
1946	kobject_set_name(&comedi_cdev.kobj, "comedi");
1947	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1948		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1949					 COMEDI_NUM_MINORS);
1950		return -EIO;
1951	}
1952	comedi_class = class_create(THIS_MODULE, "comedi");
1953	if (IS_ERR(comedi_class)) {
1954		printk(KERN_ERR "comedi: failed to create class");
1955		cdev_del(&comedi_cdev);
1956		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1957					 COMEDI_NUM_MINORS);
1958		return PTR_ERR(comedi_class);
1959	}
1960
1961	/* XXX requires /proc interface */
1962	comedi_proc_init();
1963
1964	/* create devices files for legacy/manual use */
1965	for (i = 0; i < comedi_num_legacy_minors; i++) {
1966		int minor;
1967		minor = comedi_alloc_board_minor(NULL);
1968		if (minor < 0) {
1969			comedi_cleanup_legacy_minors();
1970			cdev_del(&comedi_cdev);
1971			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1972						 COMEDI_NUM_MINORS);
1973			return minor;
1974		}
1975	}
1976
1977	return 0;
1978}
1979
1980static void __exit comedi_cleanup(void)
1981{
1982	int i;
1983
1984	comedi_cleanup_legacy_minors();
1985	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1986		BUG_ON(comedi_file_info_table[i]);
1987
1988	class_destroy(comedi_class);
1989	cdev_del(&comedi_cdev);
1990	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1991
1992	comedi_proc_cleanup();
1993}
1994
1995module_init(comedi_init);
1996module_exit(comedi_cleanup);
1997
1998void comedi_error(const struct comedi_device *dev, const char *s)
1999{
2000	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
2001	       dev->driver->driver_name, s);
2002}
2003EXPORT_SYMBOL(comedi_error);
2004
2005void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2006{
2007	struct comedi_async *async = s->async;
2008	unsigned runflags = 0;
2009	unsigned runflags_mask = 0;
2010
2011	/* DPRINTK("comedi_event 0x%x\n",mask); */
2012
2013	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2014		return;
2015
2016	if (s->
2017	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2018			     COMEDI_CB_OVERFLOW)) {
2019		runflags_mask |= SRF_RUNNING;
2020	}
2021	/* remember if an error event has occured, so an error
2022	 * can be returned the next time the user does a read() */
2023	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2024		runflags_mask |= SRF_ERROR;
2025		runflags |= SRF_ERROR;
2026	}
2027	if (runflags_mask) {
2028		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2029		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2030	}
2031
2032	if (async->cb_mask & s->async->events) {
2033		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2034			wake_up_interruptible(&async->wait_head);
2035			if (s->subdev_flags & SDF_CMD_READ)
2036				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2037			if (s->subdev_flags & SDF_CMD_WRITE)
2038				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2039		} else {
2040			if (async->cb_func)
2041				async->cb_func(s->async->events, async->cb_arg);
2042		}
2043	}
2044	s->async->events = 0;
2045}
2046EXPORT_SYMBOL(comedi_event);
2047
2048unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2049{
2050	unsigned long flags;
2051	unsigned runflags;
2052
2053	spin_lock_irqsave(&s->spin_lock, flags);
2054	runflags = s->runflags;
2055	spin_unlock_irqrestore(&s->spin_lock, flags);
2056	return runflags;
2057}
2058EXPORT_SYMBOL(comedi_get_subdevice_runflags);
2059
2060static int is_device_busy(struct comedi_device *dev)
2061{
2062	struct comedi_subdevice *s;
2063	int i;
2064
2065	if (!dev->attached)
2066		return 0;
2067
2068	for (i = 0; i < dev->n_subdevices; i++) {
2069		s = dev->subdevices + i;
2070		if (s->busy)
2071			return 1;
2072		if (s->async && s->async->mmap_count)
2073			return 1;
2074	}
2075
2076	return 0;
2077}
2078
2079static void comedi_device_init(struct comedi_device *dev)
2080{
2081	memset(dev, 0, sizeof(struct comedi_device));
2082	spin_lock_init(&dev->spinlock);
2083	mutex_init(&dev->mutex);
2084	dev->minor = -1;
2085}
2086
2087static void comedi_device_cleanup(struct comedi_device *dev)
2088{
2089	if (dev == NULL)
2090		return;
2091	mutex_lock(&dev->mutex);
2092	comedi_device_detach(dev);
2093	mutex_unlock(&dev->mutex);
2094	mutex_destroy(&dev->mutex);
2095}
2096
2097int comedi_alloc_board_minor(struct device *hardware_device)
2098{
2099	unsigned long flags;
2100	struct comedi_device_file_info *info;
2101	struct device *csdev;
2102	unsigned i;
2103	int retval;
2104
2105	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2106	if (info == NULL)
2107		return -ENOMEM;
2108	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2109	if (info->device == NULL) {
2110		kfree(info);
2111		return -ENOMEM;
2112	}
2113	comedi_device_init(info->device);
2114	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2115	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2116		if (comedi_file_info_table[i] == NULL) {
2117			comedi_file_info_table[i] = info;
2118			break;
2119		}
2120	}
2121	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2122	if (i == COMEDI_NUM_BOARD_MINORS) {
2123		comedi_device_cleanup(info->device);
2124		kfree(info->device);
2125		kfree(info);
2126		printk(KERN_ERR
2127		       "comedi: error: "
2128		       "ran out of minor numbers for board device files.\n");
2129		return -EBUSY;
2130	}
2131	info->device->minor = i;
2132	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2133				     MKDEV(COMEDI_MAJOR, i), NULL,
2134				     hardware_device, "comedi%i", i);
2135	if (!IS_ERR(csdev))
2136		info->device->class_dev = csdev;
2137	dev_set_drvdata(csdev, info);
2138	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2139	if (retval) {
2140		printk(KERN_ERR
2141		       "comedi: "
2142		       "failed to create sysfs attribute file \"%s\".\n",
2143		       dev_attr_max_read_buffer_kb.attr.name);
2144		comedi_free_board_minor(i);
2145		return retval;
2146	}
2147	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2148	if (retval) {
2149		printk(KERN_ERR
2150		       "comedi: "
2151		       "failed to create sysfs attribute file \"%s\".\n",
2152		       dev_attr_read_buffer_kb.attr.name);
2153		comedi_free_board_minor(i);
2154		return retval;
2155	}
2156	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2157	if (retval) {
2158		printk(KERN_ERR
2159		       "comedi: "
2160		       "failed to create sysfs attribute file \"%s\".\n",
2161		       dev_attr_max_write_buffer_kb.attr.name);
2162		comedi_free_board_minor(i);
2163		return retval;
2164	}
2165	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2166	if (retval) {
2167		printk(KERN_ERR
2168		       "comedi: "
2169		       "failed to create sysfs attribute file \"%s\".\n",
2170		       dev_attr_write_buffer_kb.attr.name);
2171		comedi_free_board_minor(i);
2172		return retval;
2173	}
2174	return i;
2175}
2176
2177void comedi_free_board_minor(unsigned minor)
2178{
2179	unsigned long flags;
2180	struct comedi_device_file_info *info;
2181
2182	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2183	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2184	info = comedi_file_info_table[minor];
2185	comedi_file_info_table[minor] = NULL;
2186	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2187
2188	if (info) {
2189		struct comedi_device *dev = info->device;
2190		if (dev) {
2191			if (dev->class_dev) {
2192				device_destroy(comedi_class,
2193					       MKDEV(COMEDI_MAJOR, dev->minor));
2194			}
2195			comedi_device_cleanup(dev);
2196			kfree(dev);
2197		}
2198		kfree(info);
2199	}
2200}
2201
2202int comedi_alloc_subdevice_minor(struct comedi_device *dev,
2203				 struct comedi_subdevice *s)
2204{
2205	unsigned long flags;
2206	struct comedi_device_file_info *info;
2207	struct device *csdev;
2208	unsigned i;
2209	int retval;
2210
2211	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2212	if (info == NULL)
2213		return -ENOMEM;
2214	info->device = dev;
2215	info->read_subdevice = s;
2216	info->write_subdevice = s;
2217	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2218	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2219		if (comedi_file_info_table[i] == NULL) {
2220			comedi_file_info_table[i] = info;
2221			break;
2222		}
2223	}
2224	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2225	if (i == COMEDI_NUM_MINORS) {
2226		kfree(info);
2227		printk(KERN_ERR
2228		       "comedi: error: "
2229		       "ran out of minor numbers for board device files.\n");
2230		return -EBUSY;
2231	}
2232	s->minor = i;
2233	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2234				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2235				     "comedi%i_subd%i", dev->minor,
2236				     (int)(s - dev->subdevices));
2237	if (!IS_ERR(csdev))
2238		s->class_dev = csdev;
2239	dev_set_drvdata(csdev, info);
2240	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2241	if (retval) {
2242		printk(KERN_ERR
2243		       "comedi: "
2244		       "failed to create sysfs attribute file \"%s\".\n",
2245		       dev_attr_max_read_buffer_kb.attr.name);
2246		comedi_free_subdevice_minor(s);
2247		return retval;
2248	}
2249	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2250	if (retval) {
2251		printk(KERN_ERR
2252		       "comedi: "
2253		       "failed to create sysfs attribute file \"%s\".\n",
2254		       dev_attr_read_buffer_kb.attr.name);
2255		comedi_free_subdevice_minor(s);
2256		return retval;
2257	}
2258	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2259	if (retval) {
2260		printk(KERN_ERR
2261		       "comedi: "
2262		       "failed to create sysfs attribute file \"%s\".\n",
2263		       dev_attr_max_write_buffer_kb.attr.name);
2264		comedi_free_subdevice_minor(s);
2265		return retval;
2266	}
2267	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2268	if (retval) {
2269		printk(KERN_ERR
2270		       "comedi: "
2271		       "failed to create sysfs attribute file \"%s\".\n",
2272		       dev_attr_write_buffer_kb.attr.name);
2273		comedi_free_subdevice_minor(s);
2274		return retval;
2275	}
2276	return i;
2277}
2278
2279void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2280{
2281	unsigned long flags;
2282	struct comedi_device_file_info *info;
2283
2284	if (s == NULL)
2285		return;
2286	if (s->minor < 0)
2287		return;
2288
2289	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2290	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2291
2292	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2293	info = comedi_file_info_table[s->minor];
2294	comedi_file_info_table[s->minor] = NULL;
2295	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2296
2297	if (s->class_dev) {
2298		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2299		s->class_dev = NULL;
2300	}
2301	kfree(info);
2302}
2303
2304struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2305{
2306	unsigned long flags;
2307	struct comedi_device_file_info *info;
2308
2309	BUG_ON(minor >= COMEDI_NUM_MINORS);
2310	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2311	info = comedi_file_info_table[minor];
2312	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2313	return info;
2314}
2315EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
2316
2317static int resize_async_buffer(struct comedi_device *dev,
2318			       struct comedi_subdevice *s,
2319			       struct comedi_async *async, unsigned new_size)
2320{
2321	int retval;
2322
2323	if (new_size > async->max_bufsize)
2324		return -EPERM;
2325
2326	if (s->busy) {
2327		DPRINTK("subdevice is busy, cannot resize buffer\n");
2328		return -EBUSY;
2329	}
2330	if (async->mmap_count) {
2331		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2332		return -EBUSY;
2333	}
2334
2335	if (!async->prealloc_buf)
2336		return -EINVAL;
2337
2338	/* make sure buffer is an integral number of pages
2339	 * (we round up) */
2340	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2341
2342	retval = comedi_buf_alloc(dev, s, new_size);
2343	if (retval < 0)
2344		return retval;
2345
2346	if (s->buf_change) {
2347		retval = s->buf_change(dev, s, new_size);
2348		if (retval < 0)
2349			return retval;
2350	}
2351
2352	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2353		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2354	return 0;
2355}
2356
2357/* sysfs attribute files */
2358
2359static const unsigned bytes_per_kibi = 1024;
2360
2361static ssize_t show_max_read_buffer_kb(struct device *dev,
2362				       struct device_attribute *attr, char *buf)
2363{
2364	ssize_t retval;
2365	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2366	unsigned max_buffer_size_kb = 0;
2367	struct comedi_subdevice *const read_subdevice =
2368	    comedi_get_read_subdevice(info);
2369
2370	mutex_lock(&info->device->mutex);
2371	if (read_subdevice &&
2372	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2373	    read_subdevice->async) {
2374		max_buffer_size_kb = read_subdevice->async->max_bufsize /
2375		    bytes_per_kibi;
2376	}
2377	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2378	mutex_unlock(&info->device->mutex);
2379
2380	return retval;
2381}
2382
2383static ssize_t store_max_read_buffer_kb(struct device *dev,
2384					struct device_attribute *attr,
2385					const char *buf, size_t count)
2386{
2387	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2388	unsigned long new_max_size_kb;
2389	uint64_t new_max_size;
2390	struct comedi_subdevice *const read_subdevice =
2391	    comedi_get_read_subdevice(info);
2392
2393	if (strict_strtoul(buf, 10, &new_max_size_kb))
2394		return -EINVAL;
2395	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2396		return -EINVAL;
2397	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
2398	if (new_max_size != (uint32_t) new_max_size)
2399		return -EINVAL;
2400
2401	mutex_lock(&info->device->mutex);
2402	if (read_subdevice == NULL ||
2403	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2404	    read_subdevice->async == NULL) {
2405		mutex_unlock(&info->device->mutex);
2406		return -EINVAL;
2407	}
2408	read_subdevice->async->max_bufsize = new_max_size;
2409	mutex_unlock(&info->device->mutex);
2410
2411	return count;
2412}
2413
2414static struct device_attribute dev_attr_max_read_buffer_kb = {
2415	.attr = {
2416		 .name = "max_read_buffer_kb",
2417		 .mode = S_IRUGO | S_IWUSR},
2418	.show = &show_max_read_buffer_kb,
2419	.store = &store_max_read_buffer_kb
2420};
2421
2422static ssize_t show_read_buffer_kb(struct device *dev,
2423				   struct device_attribute *attr, char *buf)
2424{
2425	ssize_t retval;
2426	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2427	unsigned buffer_size_kb = 0;
2428	struct comedi_subdevice *const read_subdevice =
2429	    comedi_get_read_subdevice(info);
2430
2431	mutex_lock(&info->device->mutex);
2432	if (read_subdevice &&
2433	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2434	    read_subdevice->async) {
2435		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
2436		    bytes_per_kibi;
2437	}
2438	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2439	mutex_unlock(&info->device->mutex);
2440
2441	return retval;
2442}
2443
2444static ssize_t store_read_buffer_kb(struct device *dev,
2445				    struct device_attribute *attr,
2446				    const char *buf, size_t count)
2447{
2448	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2449	unsigned long new_size_kb;
2450	uint64_t new_size;
2451	int retval;
2452	struct comedi_subdevice *const read_subdevice =
2453	    comedi_get_read_subdevice(info);
2454
2455	if (strict_strtoul(buf, 10, &new_size_kb))
2456		return -EINVAL;
2457	if (new_size_kb != (uint32_t) new_size_kb)
2458		return -EINVAL;
2459	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2460	if (new_size != (uint32_t) new_size)
2461		return -EINVAL;
2462
2463	mutex_lock(&info->device->mutex);
2464	if (read_subdevice == NULL ||
2465	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2466	    read_subdevice->async == NULL) {
2467		mutex_unlock(&info->device->mutex);
2468		return -EINVAL;
2469	}
2470	retval = resize_async_buffer(info->device, read_subdevice,
2471				     read_subdevice->async, new_size);
2472	mutex_unlock(&info->device->mutex);
2473
2474	if (retval < 0)
2475		return retval;
2476	return count;
2477}
2478
2479static struct device_attribute dev_attr_read_buffer_kb = {
2480	.attr = {
2481		 .name = "read_buffer_kb",
2482		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2483	.show = &show_read_buffer_kb,
2484	.store = &store_read_buffer_kb
2485};
2486
2487static ssize_t show_max_write_buffer_kb(struct device *dev,
2488					struct device_attribute *attr,
2489					char *buf)
2490{
2491	ssize_t retval;
2492	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2493	unsigned max_buffer_size_kb = 0;
2494	struct comedi_subdevice *const write_subdevice =
2495	    comedi_get_write_subdevice(info);
2496
2497	mutex_lock(&info->device->mutex);
2498	if (write_subdevice &&
2499	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2500	    write_subdevice->async) {
2501		max_buffer_size_kb = write_subdevice->async->max_bufsize /
2502		    bytes_per_kibi;
2503	}
2504	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2505	mutex_unlock(&info->device->mutex);
2506
2507	return retval;
2508}
2509
2510static ssize_t store_max_write_buffer_kb(struct device *dev,
2511					 struct device_attribute *attr,
2512					 const char *buf, size_t count)
2513{
2514	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2515	unsigned long new_max_size_kb;
2516	uint64_t new_max_size;
2517	struct comedi_subdevice *const write_subdevice =
2518	    comedi_get_write_subdevice(info);
2519
2520	if (strict_strtoul(buf, 10, &new_max_size_kb))
2521		return -EINVAL;
2522	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2523		return -EINVAL;
2524	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
2525	if (new_max_size != (uint32_t) new_max_size)
2526		return -EINVAL;
2527
2528	mutex_lock(&info->device->mutex);
2529	if (write_subdevice == NULL ||
2530	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2531	    write_subdevice->async == NULL) {
2532		mutex_unlock(&info->device->mutex);
2533		return -EINVAL;
2534	}
2535	write_subdevice->async->max_bufsize = new_max_size;
2536	mutex_unlock(&info->device->mutex);
2537
2538	return count;
2539}
2540
2541static struct device_attribute dev_attr_max_write_buffer_kb = {
2542	.attr = {
2543		 .name = "max_write_buffer_kb",
2544		 .mode = S_IRUGO | S_IWUSR},
2545	.show = &show_max_write_buffer_kb,
2546	.store = &store_max_write_buffer_kb
2547};
2548
2549static ssize_t show_write_buffer_kb(struct device *dev,
2550				    struct device_attribute *attr, char *buf)
2551{
2552	ssize_t retval;
2553	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2554	unsigned buffer_size_kb = 0;
2555	struct comedi_subdevice *const write_subdevice =
2556	    comedi_get_write_subdevice(info);
2557
2558	mutex_lock(&info->device->mutex);
2559	if (write_subdevice &&
2560	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2561	    write_subdevice->async) {
2562		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
2563		    bytes_per_kibi;
2564	}
2565	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2566	mutex_unlock(&info->device->mutex);
2567
2568	return retval;
2569}
2570
2571static ssize_t store_write_buffer_kb(struct device *dev,
2572				     struct device_attribute *attr,
2573				     const char *buf, size_t count)
2574{
2575	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2576	unsigned long new_size_kb;
2577	uint64_t new_size;
2578	int retval;
2579	struct comedi_subdevice *const write_subdevice =
2580	    comedi_get_write_subdevice(info);
2581
2582	if (strict_strtoul(buf, 10, &new_size_kb))
2583		return -EINVAL;
2584	if (new_size_kb != (uint32_t) new_size_kb)
2585		return -EINVAL;
2586	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2587	if (new_size != (uint32_t) new_size)
2588		return -EINVAL;
2589
2590	mutex_lock(&info->device->mutex);
2591	if (write_subdevice == NULL ||
2592	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2593	    write_subdevice->async == NULL) {
2594		mutex_unlock(&info->device->mutex);
2595		return -EINVAL;
2596	}
2597	retval = resize_async_buffer(info->device, write_subdevice,
2598				     write_subdevice->async, new_size);
2599	mutex_unlock(&info->device->mutex);
2600
2601	if (retval < 0)
2602		return retval;
2603	return count;
2604}
2605
2606static struct device_attribute dev_attr_write_buffer_kb = {
2607	.attr = {
2608		 .name = "write_buffer_kb",
2609		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2610	.show = &show_write_buffer_kb,
2611	.store = &store_write_buffer_kb
2612};
2613