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