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