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