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