comedi_fops.c revision d261154057c27f6c1d256b6198b0ad08733f1758
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		if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1580			if (count == 0) {
1581				if (comedi_get_subdevice_runflags(s) &
1582					SRF_ERROR) {
1583					retval = -EPIPE;
1584				} else {
1585					retval = 0;
1586				}
1587				do_become_nonbusy(dev, s);
1588			}
1589			break;
1590		}
1591
1592		n = nbytes;
1593
1594		m = n;
1595		if (async->buf_write_ptr + m > async->prealloc_bufsz)
1596			m = async->prealloc_bufsz - async->buf_write_ptr;
1597		comedi_buf_write_alloc(async, async->prealloc_bufsz);
1598		if (m > comedi_buf_write_n_allocated(async))
1599			m = comedi_buf_write_n_allocated(async);
1600		if (m < n)
1601			n = m;
1602
1603		if (n == 0) {
1604			if (file->f_flags & O_NONBLOCK) {
1605				retval = -EAGAIN;
1606				break;
1607			}
1608			if (signal_pending(current)) {
1609				retval = -ERESTARTSYS;
1610				break;
1611			}
1612			schedule();
1613			if (!s->busy)
1614				break;
1615			if (s->busy != file) {
1616				retval = -EACCES;
1617				break;
1618			}
1619			continue;
1620		}
1621
1622		m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
1623				   buf, n);
1624		if (m) {
1625			n -= m;
1626			retval = -EFAULT;
1627		}
1628		comedi_buf_write_free(async, n);
1629
1630		count += n;
1631		nbytes -= n;
1632
1633		buf += n;
1634		break;		/* makes device work like a pipe */
1635	}
1636	set_current_state(TASK_RUNNING);
1637	remove_wait_queue(&async->wait_head, &wait);
1638
1639done:
1640	return count ? count : retval;
1641}
1642
1643static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
1644				loff_t *offset)
1645{
1646	struct comedi_subdevice *s;
1647	struct comedi_async *async;
1648	int n, m, count = 0, retval = 0;
1649	DECLARE_WAITQUEUE(wait, current);
1650	const unsigned minor = iminor(file->f_dentry->d_inode);
1651	struct comedi_device_file_info *dev_file_info =
1652	    comedi_get_device_file_info(minor);
1653	struct comedi_device *dev = dev_file_info->device;
1654
1655	if (!dev->attached) {
1656		DPRINTK("no driver configured on comedi%i\n", dev->minor);
1657		retval = -ENODEV;
1658		goto done;
1659	}
1660
1661	s = comedi_get_read_subdevice(dev_file_info);
1662	if (s == NULL) {
1663		retval = -EIO;
1664		goto done;
1665	}
1666	async = s->async;
1667	if (!nbytes) {
1668		retval = 0;
1669		goto done;
1670	}
1671	if (!s->busy) {
1672		retval = 0;
1673		goto done;
1674	}
1675	if (s->busy != file) {
1676		retval = -EACCES;
1677		goto done;
1678	}
1679
1680	add_wait_queue(&async->wait_head, &wait);
1681	while (nbytes > 0 && !retval) {
1682		set_current_state(TASK_INTERRUPTIBLE);
1683
1684		n = nbytes;
1685
1686		m = comedi_buf_read_n_available(async);
1687		/* printk("%d available\n",m); */
1688		if (async->buf_read_ptr + m > async->prealloc_bufsz)
1689			m = async->prealloc_bufsz - async->buf_read_ptr;
1690		/* printk("%d contiguous\n",m); */
1691		if (m < n)
1692			n = m;
1693
1694		if (n == 0) {
1695			if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1696				do_become_nonbusy(dev, s);
1697				if (comedi_get_subdevice_runflags(s) &
1698				    SRF_ERROR) {
1699					retval = -EPIPE;
1700				} else {
1701					retval = 0;
1702				}
1703				break;
1704			}
1705			if (file->f_flags & O_NONBLOCK) {
1706				retval = -EAGAIN;
1707				break;
1708			}
1709			if (signal_pending(current)) {
1710				retval = -ERESTARTSYS;
1711				break;
1712			}
1713			schedule();
1714			if (!s->busy) {
1715				retval = 0;
1716				break;
1717			}
1718			if (s->busy != file) {
1719				retval = -EACCES;
1720				break;
1721			}
1722			continue;
1723		}
1724		m = copy_to_user(buf, async->prealloc_buf +
1725				 async->buf_read_ptr, n);
1726		if (m) {
1727			n -= m;
1728			retval = -EFAULT;
1729		}
1730
1731		comedi_buf_read_alloc(async, n);
1732		comedi_buf_read_free(async, n);
1733
1734		count += n;
1735		nbytes -= n;
1736
1737		buf += n;
1738		break;		/* makes device work like a pipe */
1739	}
1740	if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
1741	    async->buf_read_count - async->buf_write_count == 0) {
1742		do_become_nonbusy(dev, s);
1743	}
1744	set_current_state(TASK_RUNNING);
1745	remove_wait_queue(&async->wait_head, &wait);
1746
1747done:
1748	return count ? count : retval;
1749}
1750
1751/*
1752   This function restores a subdevice to an idle state.
1753 */
1754void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
1755{
1756	struct comedi_async *async = s->async;
1757
1758	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
1759	if (async) {
1760		comedi_reset_async_buf(async);
1761		async->inttrig = NULL;
1762	} else {
1763		printk(KERN_ERR
1764		       "BUG: (?) do_become_nonbusy called with async=0\n");
1765	}
1766
1767	s->busy = NULL;
1768}
1769
1770static int comedi_open(struct inode *inode, struct file *file)
1771{
1772	const unsigned minor = iminor(inode);
1773	struct comedi_device_file_info *dev_file_info =
1774	    comedi_get_device_file_info(minor);
1775	struct comedi_device *dev =
1776	    dev_file_info ? dev_file_info->device : NULL;
1777
1778	if (dev == NULL) {
1779		DPRINTK("invalid minor number\n");
1780		return -ENODEV;
1781	}
1782
1783	/* This is slightly hacky, but we want module autoloading
1784	 * to work for root.
1785	 * case: user opens device, attached -> ok
1786	 * case: user opens device, unattached, in_request_module=0 -> autoload
1787	 * case: user opens device, unattached, in_request_module=1 -> fail
1788	 * case: root opens device, attached -> ok
1789	 * case: root opens device, unattached, in_request_module=1 -> ok
1790	 *   (typically called from modprobe)
1791	 * case: root opens device, unattached, in_request_module=0 -> autoload
1792	 *
1793	 * The last could be changed to "-> ok", which would deny root
1794	 * autoloading.
1795	 */
1796	mutex_lock(&dev->mutex);
1797	if (dev->attached)
1798		goto ok;
1799	if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
1800		DPRINTK("in request module\n");
1801		mutex_unlock(&dev->mutex);
1802		return -ENODEV;
1803	}
1804	if (capable(CAP_NET_ADMIN) && dev->in_request_module)
1805		goto ok;
1806
1807	dev->in_request_module = 1;
1808
1809#ifdef CONFIG_KMOD
1810	mutex_unlock(&dev->mutex);
1811	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1812	mutex_lock(&dev->mutex);
1813#endif
1814
1815	dev->in_request_module = 0;
1816
1817	if (!dev->attached && !capable(CAP_NET_ADMIN)) {
1818		DPRINTK("not attached and not CAP_NET_ADMIN\n");
1819		mutex_unlock(&dev->mutex);
1820		return -ENODEV;
1821	}
1822ok:
1823	__module_get(THIS_MODULE);
1824
1825	if (dev->attached) {
1826		if (!try_module_get(dev->driver->module)) {
1827			module_put(THIS_MODULE);
1828			mutex_unlock(&dev->mutex);
1829			return -ENOSYS;
1830		}
1831	}
1832
1833	if (dev->attached && dev->use_count == 0 && dev->open)
1834		dev->open(dev);
1835
1836	dev->use_count++;
1837
1838	mutex_unlock(&dev->mutex);
1839
1840	return 0;
1841}
1842
1843static int comedi_close(struct inode *inode, struct file *file)
1844{
1845	const unsigned minor = iminor(inode);
1846	struct comedi_device_file_info *dev_file_info =
1847	    comedi_get_device_file_info(minor);
1848	struct comedi_device *dev = dev_file_info->device;
1849	struct comedi_subdevice *s = NULL;
1850	int i;
1851
1852	mutex_lock(&dev->mutex);
1853
1854	if (dev->subdevices) {
1855		for (i = 0; i < dev->n_subdevices; i++) {
1856			s = dev->subdevices + i;
1857
1858			if (s->busy == file)
1859				do_cancel(dev, s);
1860			if (s->lock == file)
1861				s->lock = NULL;
1862		}
1863	}
1864	if (dev->attached && dev->use_count == 1 && dev->close)
1865		dev->close(dev);
1866
1867	module_put(THIS_MODULE);
1868	if (dev->attached)
1869		module_put(dev->driver->module);
1870
1871	dev->use_count--;
1872
1873	mutex_unlock(&dev->mutex);
1874
1875	if (file->f_flags & FASYNC)
1876		comedi_fasync(-1, file, 0);
1877
1878	return 0;
1879}
1880
1881static int comedi_fasync(int fd, struct file *file, int on)
1882{
1883	const unsigned minor = iminor(file->f_dentry->d_inode);
1884	struct comedi_device_file_info *dev_file_info =
1885	    comedi_get_device_file_info(minor);
1886
1887	struct comedi_device *dev = dev_file_info->device;
1888
1889	return fasync_helper(fd, file, on, &dev->async_queue);
1890}
1891
1892const struct file_operations comedi_fops = {
1893	.owner = THIS_MODULE,
1894	.unlocked_ioctl = comedi_unlocked_ioctl,
1895	.compat_ioctl = comedi_compat_ioctl,
1896	.open = comedi_open,
1897	.release = comedi_close,
1898	.read = comedi_read,
1899	.write = comedi_write,
1900	.mmap = comedi_mmap,
1901	.poll = comedi_poll,
1902	.fasync = comedi_fasync,
1903};
1904
1905struct class *comedi_class;
1906static struct cdev comedi_cdev;
1907
1908static void comedi_cleanup_legacy_minors(void)
1909{
1910	unsigned i;
1911
1912	for (i = 0; i < comedi_num_legacy_minors; i++)
1913		comedi_free_board_minor(i);
1914}
1915
1916static int __init comedi_init(void)
1917{
1918	int i;
1919	int retval;
1920
1921	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1922	       " - http://www.comedi.org\n");
1923
1924	if (comedi_num_legacy_minors < 0 ||
1925	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1926		printk(KERN_ERR "comedi: error: invalid value for module "
1927		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1928		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1929		return -EINVAL;
1930	}
1931
1932	/*
1933	 * comedi is unusable if both comedi_autoconfig and
1934	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1935	 * defaults in that case
1936	 */
1937	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1938		comedi_num_legacy_minors = 16;
1939
1940	memset(comedi_file_info_table, 0,
1941	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1942
1943	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1944					COMEDI_NUM_MINORS, "comedi");
1945	if (retval)
1946		return -EIO;
1947	cdev_init(&comedi_cdev, &comedi_fops);
1948	comedi_cdev.owner = THIS_MODULE;
1949	kobject_set_name(&comedi_cdev.kobj, "comedi");
1950	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1951		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1952					 COMEDI_NUM_MINORS);
1953		return -EIO;
1954	}
1955	comedi_class = class_create(THIS_MODULE, "comedi");
1956	if (IS_ERR(comedi_class)) {
1957		printk(KERN_ERR "comedi: failed to create class");
1958		cdev_del(&comedi_cdev);
1959		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1960					 COMEDI_NUM_MINORS);
1961		return PTR_ERR(comedi_class);
1962	}
1963
1964	/* XXX requires /proc interface */
1965	comedi_proc_init();
1966
1967	/* create devices files for legacy/manual use */
1968	for (i = 0; i < comedi_num_legacy_minors; i++) {
1969		int minor;
1970		minor = comedi_alloc_board_minor(NULL);
1971		if (minor < 0) {
1972			comedi_cleanup_legacy_minors();
1973			cdev_del(&comedi_cdev);
1974			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1975						 COMEDI_NUM_MINORS);
1976			return minor;
1977		}
1978	}
1979
1980	return 0;
1981}
1982
1983static void __exit comedi_cleanup(void)
1984{
1985	int i;
1986
1987	comedi_cleanup_legacy_minors();
1988	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1989		BUG_ON(comedi_file_info_table[i]);
1990
1991	class_destroy(comedi_class);
1992	cdev_del(&comedi_cdev);
1993	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1994
1995	comedi_proc_cleanup();
1996}
1997
1998module_init(comedi_init);
1999module_exit(comedi_cleanup);
2000
2001void comedi_error(const struct comedi_device *dev, const char *s)
2002{
2003	printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
2004	       dev->driver->driver_name, s);
2005}
2006EXPORT_SYMBOL(comedi_error);
2007
2008void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2009{
2010	struct comedi_async *async = s->async;
2011	unsigned runflags = 0;
2012	unsigned runflags_mask = 0;
2013
2014	/* DPRINTK("comedi_event 0x%x\n",mask); */
2015
2016	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2017		return;
2018
2019	if (s->
2020	    async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2021			     COMEDI_CB_OVERFLOW)) {
2022		runflags_mask |= SRF_RUNNING;
2023	}
2024	/* remember if an error event has occured, so an error
2025	 * can be returned the next time the user does a read() */
2026	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2027		runflags_mask |= SRF_ERROR;
2028		runflags |= SRF_ERROR;
2029	}
2030	if (runflags_mask) {
2031		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2032		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2033	}
2034
2035	if (async->cb_mask & s->async->events) {
2036		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2037			wake_up_interruptible(&async->wait_head);
2038			if (s->subdev_flags & SDF_CMD_READ)
2039				kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2040			if (s->subdev_flags & SDF_CMD_WRITE)
2041				kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2042		} else {
2043			if (async->cb_func)
2044				async->cb_func(s->async->events, async->cb_arg);
2045		}
2046	}
2047	s->async->events = 0;
2048}
2049EXPORT_SYMBOL(comedi_event);
2050
2051unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2052{
2053	unsigned long flags;
2054	unsigned runflags;
2055
2056	spin_lock_irqsave(&s->spin_lock, flags);
2057	runflags = s->runflags;
2058	spin_unlock_irqrestore(&s->spin_lock, flags);
2059	return runflags;
2060}
2061EXPORT_SYMBOL(comedi_get_subdevice_runflags);
2062
2063static int is_device_busy(struct comedi_device *dev)
2064{
2065	struct comedi_subdevice *s;
2066	int i;
2067
2068	if (!dev->attached)
2069		return 0;
2070
2071	for (i = 0; i < dev->n_subdevices; i++) {
2072		s = dev->subdevices + i;
2073		if (s->busy)
2074			return 1;
2075		if (s->async && s->async->mmap_count)
2076			return 1;
2077	}
2078
2079	return 0;
2080}
2081
2082static void comedi_device_init(struct comedi_device *dev)
2083{
2084	memset(dev, 0, sizeof(struct comedi_device));
2085	spin_lock_init(&dev->spinlock);
2086	mutex_init(&dev->mutex);
2087	dev->minor = -1;
2088}
2089
2090static void comedi_device_cleanup(struct comedi_device *dev)
2091{
2092	if (dev == NULL)
2093		return;
2094	mutex_lock(&dev->mutex);
2095	comedi_device_detach(dev);
2096	mutex_unlock(&dev->mutex);
2097	mutex_destroy(&dev->mutex);
2098}
2099
2100int comedi_alloc_board_minor(struct device *hardware_device)
2101{
2102	unsigned long flags;
2103	struct comedi_device_file_info *info;
2104	struct device *csdev;
2105	unsigned i;
2106	int retval;
2107
2108	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2109	if (info == NULL)
2110		return -ENOMEM;
2111	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2112	if (info->device == NULL) {
2113		kfree(info);
2114		return -ENOMEM;
2115	}
2116	comedi_device_init(info->device);
2117	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2118	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2119		if (comedi_file_info_table[i] == NULL) {
2120			comedi_file_info_table[i] = info;
2121			break;
2122		}
2123	}
2124	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2125	if (i == COMEDI_NUM_BOARD_MINORS) {
2126		comedi_device_cleanup(info->device);
2127		kfree(info->device);
2128		kfree(info);
2129		printk(KERN_ERR
2130		       "comedi: error: "
2131		       "ran out of minor numbers for board device files.\n");
2132		return -EBUSY;
2133	}
2134	info->device->minor = i;
2135	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2136				     MKDEV(COMEDI_MAJOR, i), NULL,
2137				     hardware_device, "comedi%i", i);
2138	if (!IS_ERR(csdev))
2139		info->device->class_dev = csdev;
2140	dev_set_drvdata(csdev, info);
2141	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2142	if (retval) {
2143		printk(KERN_ERR
2144		       "comedi: "
2145		       "failed to create sysfs attribute file \"%s\".\n",
2146		       dev_attr_max_read_buffer_kb.attr.name);
2147		comedi_free_board_minor(i);
2148		return retval;
2149	}
2150	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2151	if (retval) {
2152		printk(KERN_ERR
2153		       "comedi: "
2154		       "failed to create sysfs attribute file \"%s\".\n",
2155		       dev_attr_read_buffer_kb.attr.name);
2156		comedi_free_board_minor(i);
2157		return retval;
2158	}
2159	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2160	if (retval) {
2161		printk(KERN_ERR
2162		       "comedi: "
2163		       "failed to create sysfs attribute file \"%s\".\n",
2164		       dev_attr_max_write_buffer_kb.attr.name);
2165		comedi_free_board_minor(i);
2166		return retval;
2167	}
2168	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2169	if (retval) {
2170		printk(KERN_ERR
2171		       "comedi: "
2172		       "failed to create sysfs attribute file \"%s\".\n",
2173		       dev_attr_write_buffer_kb.attr.name);
2174		comedi_free_board_minor(i);
2175		return retval;
2176	}
2177	return i;
2178}
2179
2180void comedi_free_board_minor(unsigned minor)
2181{
2182	unsigned long flags;
2183	struct comedi_device_file_info *info;
2184
2185	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2186	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2187	info = comedi_file_info_table[minor];
2188	comedi_file_info_table[minor] = NULL;
2189	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2190
2191	if (info) {
2192		struct comedi_device *dev = info->device;
2193		if (dev) {
2194			if (dev->class_dev) {
2195				device_destroy(comedi_class,
2196					       MKDEV(COMEDI_MAJOR, dev->minor));
2197			}
2198			comedi_device_cleanup(dev);
2199			kfree(dev);
2200		}
2201		kfree(info);
2202	}
2203}
2204
2205int comedi_alloc_subdevice_minor(struct comedi_device *dev,
2206				 struct comedi_subdevice *s)
2207{
2208	unsigned long flags;
2209	struct comedi_device_file_info *info;
2210	struct device *csdev;
2211	unsigned i;
2212	int retval;
2213
2214	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2215	if (info == NULL)
2216		return -ENOMEM;
2217	info->device = dev;
2218	info->read_subdevice = s;
2219	info->write_subdevice = s;
2220	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2221	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2222		if (comedi_file_info_table[i] == NULL) {
2223			comedi_file_info_table[i] = info;
2224			break;
2225		}
2226	}
2227	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2228	if (i == COMEDI_NUM_MINORS) {
2229		kfree(info);
2230		printk(KERN_ERR
2231		       "comedi: error: "
2232		       "ran out of minor numbers for board device files.\n");
2233		return -EBUSY;
2234	}
2235	s->minor = i;
2236	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2237				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2238				     "comedi%i_subd%i", dev->minor,
2239				     (int)(s - dev->subdevices));
2240	if (!IS_ERR(csdev))
2241		s->class_dev = csdev;
2242	dev_set_drvdata(csdev, info);
2243	retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
2244	if (retval) {
2245		printk(KERN_ERR
2246		       "comedi: "
2247		       "failed to create sysfs attribute file \"%s\".\n",
2248		       dev_attr_max_read_buffer_kb.attr.name);
2249		comedi_free_subdevice_minor(s);
2250		return retval;
2251	}
2252	retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
2253	if (retval) {
2254		printk(KERN_ERR
2255		       "comedi: "
2256		       "failed to create sysfs attribute file \"%s\".\n",
2257		       dev_attr_read_buffer_kb.attr.name);
2258		comedi_free_subdevice_minor(s);
2259		return retval;
2260	}
2261	retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
2262	if (retval) {
2263		printk(KERN_ERR
2264		       "comedi: "
2265		       "failed to create sysfs attribute file \"%s\".\n",
2266		       dev_attr_max_write_buffer_kb.attr.name);
2267		comedi_free_subdevice_minor(s);
2268		return retval;
2269	}
2270	retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
2271	if (retval) {
2272		printk(KERN_ERR
2273		       "comedi: "
2274		       "failed to create sysfs attribute file \"%s\".\n",
2275		       dev_attr_write_buffer_kb.attr.name);
2276		comedi_free_subdevice_minor(s);
2277		return retval;
2278	}
2279	return i;
2280}
2281
2282void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2283{
2284	unsigned long flags;
2285	struct comedi_device_file_info *info;
2286
2287	if (s == NULL)
2288		return;
2289	if (s->minor < 0)
2290		return;
2291
2292	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2293	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2294
2295	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2296	info = comedi_file_info_table[s->minor];
2297	comedi_file_info_table[s->minor] = NULL;
2298	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2299
2300	if (s->class_dev) {
2301		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2302		s->class_dev = NULL;
2303	}
2304	kfree(info);
2305}
2306
2307struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2308{
2309	unsigned long flags;
2310	struct comedi_device_file_info *info;
2311
2312	BUG_ON(minor >= COMEDI_NUM_MINORS);
2313	spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2314	info = comedi_file_info_table[minor];
2315	spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2316	return info;
2317}
2318EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
2319
2320static int resize_async_buffer(struct comedi_device *dev,
2321			       struct comedi_subdevice *s,
2322			       struct comedi_async *async, unsigned new_size)
2323{
2324	int retval;
2325
2326	if (new_size > async->max_bufsize)
2327		return -EPERM;
2328
2329	if (s->busy) {
2330		DPRINTK("subdevice is busy, cannot resize buffer\n");
2331		return -EBUSY;
2332	}
2333	if (async->mmap_count) {
2334		DPRINTK("subdevice is mmapped, cannot resize buffer\n");
2335		return -EBUSY;
2336	}
2337
2338	if (!async->prealloc_buf)
2339		return -EINVAL;
2340
2341	/* make sure buffer is an integral number of pages
2342	 * (we round up) */
2343	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
2344
2345	retval = comedi_buf_alloc(dev, s, new_size);
2346	if (retval < 0)
2347		return retval;
2348
2349	if (s->buf_change) {
2350		retval = s->buf_change(dev, s, new_size);
2351		if (retval < 0)
2352			return retval;
2353	}
2354
2355	DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
2356		dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
2357	return 0;
2358}
2359
2360/* sysfs attribute files */
2361
2362static const unsigned bytes_per_kibi = 1024;
2363
2364static ssize_t show_max_read_buffer_kb(struct device *dev,
2365				       struct device_attribute *attr, char *buf)
2366{
2367	ssize_t retval;
2368	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2369	unsigned max_buffer_size_kb = 0;
2370	struct comedi_subdevice *const read_subdevice =
2371	    comedi_get_read_subdevice(info);
2372
2373	mutex_lock(&info->device->mutex);
2374	if (read_subdevice &&
2375	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2376	    read_subdevice->async) {
2377		max_buffer_size_kb = read_subdevice->async->max_bufsize /
2378		    bytes_per_kibi;
2379	}
2380	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2381	mutex_unlock(&info->device->mutex);
2382
2383	return retval;
2384}
2385
2386static ssize_t store_max_read_buffer_kb(struct device *dev,
2387					struct device_attribute *attr,
2388					const char *buf, size_t count)
2389{
2390	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2391	unsigned long new_max_size_kb;
2392	uint64_t new_max_size;
2393	struct comedi_subdevice *const read_subdevice =
2394	    comedi_get_read_subdevice(info);
2395
2396	if (strict_strtoul(buf, 10, &new_max_size_kb))
2397		return -EINVAL;
2398	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2399		return -EINVAL;
2400	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
2401	if (new_max_size != (uint32_t) new_max_size)
2402		return -EINVAL;
2403
2404	mutex_lock(&info->device->mutex);
2405	if (read_subdevice == NULL ||
2406	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2407	    read_subdevice->async == NULL) {
2408		mutex_unlock(&info->device->mutex);
2409		return -EINVAL;
2410	}
2411	read_subdevice->async->max_bufsize = new_max_size;
2412	mutex_unlock(&info->device->mutex);
2413
2414	return count;
2415}
2416
2417static struct device_attribute dev_attr_max_read_buffer_kb = {
2418	.attr = {
2419		 .name = "max_read_buffer_kb",
2420		 .mode = S_IRUGO | S_IWUSR},
2421	.show = &show_max_read_buffer_kb,
2422	.store = &store_max_read_buffer_kb
2423};
2424
2425static ssize_t show_read_buffer_kb(struct device *dev,
2426				   struct device_attribute *attr, char *buf)
2427{
2428	ssize_t retval;
2429	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2430	unsigned buffer_size_kb = 0;
2431	struct comedi_subdevice *const read_subdevice =
2432	    comedi_get_read_subdevice(info);
2433
2434	mutex_lock(&info->device->mutex);
2435	if (read_subdevice &&
2436	    (read_subdevice->subdev_flags & SDF_CMD_READ) &&
2437	    read_subdevice->async) {
2438		buffer_size_kb = read_subdevice->async->prealloc_bufsz /
2439		    bytes_per_kibi;
2440	}
2441	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2442	mutex_unlock(&info->device->mutex);
2443
2444	return retval;
2445}
2446
2447static ssize_t store_read_buffer_kb(struct device *dev,
2448				    struct device_attribute *attr,
2449				    const char *buf, size_t count)
2450{
2451	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2452	unsigned long new_size_kb;
2453	uint64_t new_size;
2454	int retval;
2455	struct comedi_subdevice *const read_subdevice =
2456	    comedi_get_read_subdevice(info);
2457
2458	if (strict_strtoul(buf, 10, &new_size_kb))
2459		return -EINVAL;
2460	if (new_size_kb != (uint32_t) new_size_kb)
2461		return -EINVAL;
2462	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2463	if (new_size != (uint32_t) new_size)
2464		return -EINVAL;
2465
2466	mutex_lock(&info->device->mutex);
2467	if (read_subdevice == NULL ||
2468	    (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
2469	    read_subdevice->async == NULL) {
2470		mutex_unlock(&info->device->mutex);
2471		return -EINVAL;
2472	}
2473	retval = resize_async_buffer(info->device, read_subdevice,
2474				     read_subdevice->async, new_size);
2475	mutex_unlock(&info->device->mutex);
2476
2477	if (retval < 0)
2478		return retval;
2479	return count;
2480}
2481
2482static struct device_attribute dev_attr_read_buffer_kb = {
2483	.attr = {
2484		 .name = "read_buffer_kb",
2485		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2486	.show = &show_read_buffer_kb,
2487	.store = &store_read_buffer_kb
2488};
2489
2490static ssize_t show_max_write_buffer_kb(struct device *dev,
2491					struct device_attribute *attr,
2492					char *buf)
2493{
2494	ssize_t retval;
2495	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2496	unsigned max_buffer_size_kb = 0;
2497	struct comedi_subdevice *const write_subdevice =
2498	    comedi_get_write_subdevice(info);
2499
2500	mutex_lock(&info->device->mutex);
2501	if (write_subdevice &&
2502	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2503	    write_subdevice->async) {
2504		max_buffer_size_kb = write_subdevice->async->max_bufsize /
2505		    bytes_per_kibi;
2506	}
2507	retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
2508	mutex_unlock(&info->device->mutex);
2509
2510	return retval;
2511}
2512
2513static ssize_t store_max_write_buffer_kb(struct device *dev,
2514					 struct device_attribute *attr,
2515					 const char *buf, size_t count)
2516{
2517	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2518	unsigned long new_max_size_kb;
2519	uint64_t new_max_size;
2520	struct comedi_subdevice *const write_subdevice =
2521	    comedi_get_write_subdevice(info);
2522
2523	if (strict_strtoul(buf, 10, &new_max_size_kb))
2524		return -EINVAL;
2525	if (new_max_size_kb != (uint32_t) new_max_size_kb)
2526		return -EINVAL;
2527	new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi;
2528	if (new_max_size != (uint32_t) new_max_size)
2529		return -EINVAL;
2530
2531	mutex_lock(&info->device->mutex);
2532	if (write_subdevice == NULL ||
2533	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2534	    write_subdevice->async == NULL) {
2535		mutex_unlock(&info->device->mutex);
2536		return -EINVAL;
2537	}
2538	write_subdevice->async->max_bufsize = new_max_size;
2539	mutex_unlock(&info->device->mutex);
2540
2541	return count;
2542}
2543
2544static struct device_attribute dev_attr_max_write_buffer_kb = {
2545	.attr = {
2546		 .name = "max_write_buffer_kb",
2547		 .mode = S_IRUGO | S_IWUSR},
2548	.show = &show_max_write_buffer_kb,
2549	.store = &store_max_write_buffer_kb
2550};
2551
2552static ssize_t show_write_buffer_kb(struct device *dev,
2553				    struct device_attribute *attr, char *buf)
2554{
2555	ssize_t retval;
2556	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2557	unsigned buffer_size_kb = 0;
2558	struct comedi_subdevice *const write_subdevice =
2559	    comedi_get_write_subdevice(info);
2560
2561	mutex_lock(&info->device->mutex);
2562	if (write_subdevice &&
2563	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
2564	    write_subdevice->async) {
2565		buffer_size_kb = write_subdevice->async->prealloc_bufsz /
2566		    bytes_per_kibi;
2567	}
2568	retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
2569	mutex_unlock(&info->device->mutex);
2570
2571	return retval;
2572}
2573
2574static ssize_t store_write_buffer_kb(struct device *dev,
2575				     struct device_attribute *attr,
2576				     const char *buf, size_t count)
2577{
2578	struct comedi_device_file_info *info = dev_get_drvdata(dev);
2579	unsigned long new_size_kb;
2580	uint64_t new_size;
2581	int retval;
2582	struct comedi_subdevice *const write_subdevice =
2583	    comedi_get_write_subdevice(info);
2584
2585	if (strict_strtoul(buf, 10, &new_size_kb))
2586		return -EINVAL;
2587	if (new_size_kb != (uint32_t) new_size_kb)
2588		return -EINVAL;
2589	new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
2590	if (new_size != (uint32_t) new_size)
2591		return -EINVAL;
2592
2593	mutex_lock(&info->device->mutex);
2594	if (write_subdevice == NULL ||
2595	    (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
2596	    write_subdevice->async == NULL) {
2597		mutex_unlock(&info->device->mutex);
2598		return -EINVAL;
2599	}
2600	retval = resize_async_buffer(info->device, write_subdevice,
2601				     write_subdevice->async, new_size);
2602	mutex_unlock(&info->device->mutex);
2603
2604	if (retval < 0)
2605		return retval;
2606	return count;
2607}
2608
2609static struct device_attribute dev_attr_write_buffer_kb = {
2610	.attr = {
2611		 .name = "write_buffer_kb",
2612		 .mode = S_IRUGO | S_IWUSR | S_IWGRP},
2613	.show = &show_write_buffer_kb,
2614	.store = &store_write_buffer_kb
2615};
2616