comedi_fops.c revision be6aba4a423629126f318d351b2d0eb00abb9dd5
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(struct comedi_device *dev, struct comedi_devconfig *arg);
73static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
74static int do_devinfo_ioctl(struct comedi_device *dev, struct comedi_devinfo *arg,
75			    struct file *file);
76static int do_subdinfo_ioctl(struct comedi_device *dev, struct comedi_subdinfo *arg,
77			     void *file);
78static int do_chaninfo_ioctl(struct comedi_device *dev, struct comedi_chaninfo *arg);
79static int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
80static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
81static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
82static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
83static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
84static int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
85static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
86static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
87static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, void *file);
88
89extern void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s);
90static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
91
92static int comedi_fasync(int fd, struct file *file, int on);
93
94static int is_device_busy(struct 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	struct 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(struct comedi_device *dev, struct comedi_devconfig *arg)
196{
197	struct 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(struct 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(struct comedi_device *dev, void *arg)
276{
277	struct comedi_bufconfig bc;
278	struct comedi_async *async;
279	struct comedi_subdevice *s;
280	int ret = 0;
281
282	if (copy_from_user(&bc, arg, sizeof(struct 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(struct 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(struct comedi_device *dev, struct comedi_devinfo *arg,
364			    struct file *file)
365{
366	struct 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	struct comedi_subdevice *read_subdev =
371	    comedi_get_read_subdevice(dev_file_info);
372	struct 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(struct 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(struct comedi_device *dev, struct comedi_subdinfo *arg,
414			     void *file)
415{
416	int ret, i;
417	struct comedi_subdinfo *tmp, *us;
418	struct comedi_subdevice *s;
419
420	tmp = kcalloc(dev->n_subdevices, sizeof(struct 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(struct 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(struct comedi_device *dev, struct comedi_chaninfo *arg)
494{
495	struct comedi_subdevice *s;
496	struct comedi_chaninfo it;
497
498	if (copy_from_user(&it, arg, sizeof(struct 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(unsigned int)))
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(struct comedi_device *dev, void *arg)
558{
559	comedi_bufinfo bi;
560	struct comedi_subdevice *s;
561	struct 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(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *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(struct comedi_device *dev, void *arg, void *file)
630{
631	struct comedi_insnlist insnlist;
632	struct comedi_insn *insns = NULL;
633	unsigned int *data = NULL;
634	int i = 0;
635	int ret = 0;
636
637	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
638		return -EFAULT;
639
640	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
641	if (!data) {
642		DPRINTK("kmalloc failed\n");
643		ret = -ENOMEM;
644		goto error;
645	}
646
647	insns = kmalloc(sizeof(struct 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(struct 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(unsigned int))) {
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(unsigned int))) {
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(struct comedi_insn *insn, unsigned int *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(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data,
761		      void *file)
762{
763	struct 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		unsigned int 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 * 		struct comedi_insn struct at arg
915 * 		data (for writes)
916 *
917 * 	writes:
918 * 		data (for reads)
919 */
920static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
921{
922	struct comedi_insn insn;
923	unsigned int *data = NULL;
924	int ret = 0;
925
926	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
927	if (!data) {
928		ret = -ENOMEM;
929		goto error;
930	}
931
932	if (copy_from_user(&insn, arg, sizeof(struct 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(unsigned int))) {
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(unsigned int))) {
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(struct comedi_device *dev, void *arg, void *file)
979{
980	struct comedi_cmd user_cmd;
981	struct comedi_subdevice *s;
982	struct comedi_async *async;
983	int ret = 0;
984	unsigned int *chanlist_saver = NULL;
985
986	if (copy_from_user(&user_cmd, arg, sizeof(struct 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(struct 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(struct comedi_device *dev, void *arg, void *file)
1133{
1134	struct comedi_cmd user_cmd;
1135	struct 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(struct 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(struct 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(struct comedi_device *dev, unsigned int arg, void *file)
1231{
1232	int ret = 0;
1233	unsigned long flags;
1234	struct 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(struct comedi_device *dev, unsigned int arg, void *file)
1275{
1276	struct 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(struct comedi_device *dev, unsigned int arg, void *file)
1315{
1316	struct 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(struct comedi_device *dev, unsigned int arg, void *file)
1351{
1352	struct 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(struct comedi_device *dev, struct 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	struct comedi_async *async;
1388	struct 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	struct comedi_device *dev = dev_file_info->device;
1408	struct 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	struct 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	struct comedi_device *dev = dev_file_info->device;
1484	struct comedi_subdevice *read_subdev;
1485	struct 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	struct comedi_subdevice *s;
1527	struct 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	struct 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	struct comedi_subdevice *s;
1629	struct 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	struct 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(struct comedi_device *dev, struct comedi_subdevice *s)
1737{
1738	struct 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	const unsigned minor = iminor(inode);
1761	struct comedi_device_file_info *dev_file_info =
1762	    comedi_get_device_file_info(minor);
1763	struct comedi_device *dev = dev_file_info ? dev_file_info->device : NULL;
1764
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#ifdef CONFIG_KMOD
1797	mutex_unlock(&dev->mutex);
1798	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
1799	mutex_lock(&dev->mutex);
1800#endif
1801
1802	dev->in_request_module = 0;
1803
1804	if (!dev->attached && !capable(CAP_SYS_MODULE)) {
1805		DPRINTK("not attached and not CAP_SYS_MODULE\n");
1806		mutex_unlock(&dev->mutex);
1807		return -ENODEV;
1808	}
1809ok:
1810	__module_get(THIS_MODULE);
1811
1812	if (dev->attached) {
1813		if (!try_module_get(dev->driver->module)) {
1814			module_put(THIS_MODULE);
1815			mutex_unlock(&dev->mutex);
1816			return -ENOSYS;
1817		}
1818	}
1819
1820	if (dev->attached && dev->use_count == 0 && dev->open)
1821		dev->open(dev);
1822
1823	dev->use_count++;
1824
1825	mutex_unlock(&dev->mutex);
1826
1827	return 0;
1828}
1829
1830static int comedi_close(struct inode *inode, struct file *file)
1831{
1832	const unsigned minor = iminor(inode);
1833	struct comedi_device_file_info *dev_file_info =
1834	    comedi_get_device_file_info(minor);
1835	struct comedi_device *dev = dev_file_info->device;
1836	struct comedi_subdevice *s = NULL;
1837	int i;
1838
1839	mutex_lock(&dev->mutex);
1840
1841	if (dev->subdevices) {
1842		for (i = 0; i < dev->n_subdevices; i++) {
1843			s = dev->subdevices + i;
1844
1845			if (s->busy == file)
1846				do_cancel(dev, s);
1847			if (s->lock == file)
1848				s->lock = NULL;
1849		}
1850	}
1851	if (dev->attached && dev->use_count == 1 && dev->close)
1852		dev->close(dev);
1853
1854	module_put(THIS_MODULE);
1855	if (dev->attached)
1856		module_put(dev->driver->module);
1857
1858	dev->use_count--;
1859
1860	mutex_unlock(&dev->mutex);
1861
1862	if (file->f_flags & FASYNC)
1863		comedi_fasync(-1, file, 0);
1864
1865	return 0;
1866}
1867
1868static int comedi_fasync(int fd, struct file *file, int on)
1869{
1870	const unsigned minor = iminor(file->f_dentry->d_inode);
1871	struct comedi_device_file_info *dev_file_info =
1872	    comedi_get_device_file_info(minor);
1873
1874	struct comedi_device *dev = dev_file_info->device;
1875
1876	return fasync_helper(fd, file, on, &dev->async_queue);
1877}
1878
1879const struct file_operations comedi_fops = {
1880      .owner =		THIS_MODULE,
1881#ifdef HAVE_UNLOCKED_IOCTL
1882      .unlocked_ioctl =	comedi_unlocked_ioctl,
1883#else
1884      .ioctl =		comedi_ioctl,
1885#endif
1886#ifdef HAVE_COMPAT_IOCTL
1887      .compat_ioctl =	comedi_compat_ioctl,
1888#endif
1889      .open =		comedi_open,
1890      .release =	comedi_close,
1891      .read =		comedi_read,
1892      .write =		comedi_write,
1893      .mmap =		comedi_mmap,
1894      .poll =		comedi_poll,
1895      .fasync =		comedi_fasync,
1896};
1897
1898struct class *comedi_class;
1899static struct cdev comedi_cdev;
1900
1901static void comedi_cleanup_legacy_minors(void)
1902{
1903	unsigned i;
1904
1905	for (i = 0; i < comedi_num_legacy_minors; i++)
1906		comedi_free_board_minor(i);
1907}
1908
1909static int __init comedi_init(void)
1910{
1911	int i;
1912	int retval;
1913
1914	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
1915	       " - http://www.comedi.org\n");
1916
1917	if (comedi_num_legacy_minors < 0 ||
1918	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
1919		printk(KERN_ERR "comedi: error: invalid value for module "
1920		       "parameter \"comedi_num_legacy_minors\".  Valid values "
1921		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
1922		return -EINVAL;
1923	}
1924
1925	/*
1926	 * comedi is unusable if both comedi_autoconfig and
1927	 * comedi_num_legacy_minors are zero, so we might as well adjust the
1928	 * defaults in that case
1929	 */
1930	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
1931		comedi_num_legacy_minors = 16;
1932
1933	memset(comedi_file_info_table, 0,
1934	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
1935
1936	retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1937					COMEDI_NUM_MINORS, "comedi");
1938	if (retval)
1939		return -EIO;
1940	cdev_init(&comedi_cdev, &comedi_fops);
1941	comedi_cdev.owner = THIS_MODULE;
1942	kobject_set_name(&comedi_cdev.kobj, "comedi");
1943	if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
1944		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1945					 COMEDI_NUM_MINORS);
1946		return -EIO;
1947	}
1948	comedi_class = class_create(THIS_MODULE, "comedi");
1949	if (IS_ERR(comedi_class)) {
1950		printk("comedi: failed to create class");
1951		cdev_del(&comedi_cdev);
1952		unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1953					 COMEDI_NUM_MINORS);
1954		return PTR_ERR(comedi_class);
1955	}
1956
1957	/* XXX requires /proc interface */
1958	comedi_proc_init();
1959
1960	/* create devices files for legacy/manual use */
1961	for (i = 0; i < comedi_num_legacy_minors; i++) {
1962		int minor;
1963		minor = comedi_alloc_board_minor(NULL);
1964		if (minor < 0) {
1965			comedi_cleanup_legacy_minors();
1966			cdev_del(&comedi_cdev);
1967			unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
1968						 COMEDI_NUM_MINORS);
1969			return minor;
1970		}
1971	}
1972
1973	comedi_rt_init();
1974
1975	comedi_register_ioctl32();
1976
1977	return 0;
1978}
1979
1980static void __exit comedi_cleanup(void)
1981{
1982	int i;
1983
1984	comedi_cleanup_legacy_minors();
1985	for (i = 0; i < COMEDI_NUM_MINORS; ++i)
1986		BUG_ON(comedi_file_info_table[i]);
1987
1988
1989	class_destroy(comedi_class);
1990	cdev_del(&comedi_cdev);
1991	unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
1992
1993	comedi_proc_cleanup();
1994
1995	comedi_rt_cleanup();
1996
1997	comedi_unregister_ioctl32();
1998}
1999
2000module_init(comedi_init);
2001module_exit(comedi_cleanup);
2002
2003void comedi_error(const struct comedi_device *dev, const char *s)
2004{
2005	rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
2006		  s);
2007}
2008
2009void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2010{
2011	struct comedi_async *async = s->async;
2012	unsigned runflags = 0;
2013	unsigned runflags_mask = 0;
2014
2015	/* DPRINTK("comedi_event 0x%x\n",mask); */
2016
2017	if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2018		return;
2019
2020	if (s->async->
2021	    events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2022		runflags_mask |= SRF_RUNNING;
2023	}
2024	/* remember if an error event has occured, so an error
2025	 * can be returned the next time the user does a read() */
2026	if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2027		runflags_mask |= SRF_ERROR;
2028		runflags |= SRF_ERROR;
2029	}
2030	if (runflags_mask) {
2031		/*sets SRF_ERROR and SRF_RUNNING together atomically */
2032		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2033	}
2034
2035	if (async->cb_mask & s->async->events) {
2036		if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2037
2038			if (dev->rt) {
2039#ifdef CONFIG_COMEDI_RT
2040				/* pend wake up */
2041				comedi_rt_pend_wakeup(&async->wait_head);
2042#else
2043				printk
2044				    ("BUG: comedi_event() code unreachable\n");
2045#endif
2046			} else {
2047				wake_up_interruptible(&async->wait_head);
2048				if (s->subdev_flags & SDF_CMD_READ) {
2049					kill_fasync(&dev->async_queue, SIGIO,
2050						    POLL_IN);
2051				}
2052				if (s->subdev_flags & SDF_CMD_WRITE) {
2053					kill_fasync(&dev->async_queue, SIGIO,
2054						    POLL_OUT);
2055				}
2056			}
2057		} else {
2058			if (async->cb_func)
2059				async->cb_func(s->async->events, async->cb_arg);
2060			/* XXX bug here.  If subdevice A is rt, and
2061			 * subdevice B tries to callback to a normal
2062			 * linux kernel function, it will be at the
2063			 * wrong priority.  Since this isn't very
2064			 * common, I'm not going to worry about it. */
2065		}
2066	}
2067	s->async->events = 0;
2068}
2069
2070void comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
2071				   unsigned bits)
2072{
2073	unsigned long flags;
2074
2075	comedi_spin_lock_irqsave(&s->spin_lock, flags);
2076	s->runflags &= ~mask;
2077	s->runflags |= (bits & mask);
2078	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2079}
2080
2081unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
2082{
2083	unsigned long flags;
2084	unsigned runflags;
2085
2086	comedi_spin_lock_irqsave(&s->spin_lock, flags);
2087	runflags = s->runflags;
2088	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
2089	return runflags;
2090}
2091
2092static int is_device_busy(struct comedi_device *dev)
2093{
2094	struct comedi_subdevice *s;
2095	int i;
2096
2097	if (!dev->attached)
2098		return 0;
2099
2100	for (i = 0; i < dev->n_subdevices; i++) {
2101		s = dev->subdevices + i;
2102		if (s->busy)
2103			return 1;
2104		if (s->async && s->async->mmap_count)
2105			return 1;
2106	}
2107
2108	return 0;
2109}
2110
2111void comedi_device_init(struct comedi_device *dev)
2112{
2113	memset(dev, 0, sizeof(struct comedi_device));
2114	spin_lock_init(&dev->spinlock);
2115	mutex_init(&dev->mutex);
2116	dev->minor = -1;
2117}
2118
2119void comedi_device_cleanup(struct comedi_device *dev)
2120{
2121	if (dev == NULL)
2122		return;
2123	mutex_lock(&dev->mutex);
2124	comedi_device_detach(dev);
2125	mutex_unlock(&dev->mutex);
2126	mutex_destroy(&dev->mutex);
2127}
2128
2129int comedi_alloc_board_minor(struct device *hardware_device)
2130{
2131	unsigned long flags;
2132	struct comedi_device_file_info *info;
2133	struct device *csdev;
2134	unsigned i;
2135
2136	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2137	if (info == NULL)
2138		return -ENOMEM;
2139	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2140	if (info->device == NULL) {
2141		kfree(info);
2142		return -ENOMEM;
2143	}
2144	comedi_device_init(info->device);
2145	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2146	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2147		if (comedi_file_info_table[i] == NULL) {
2148			comedi_file_info_table[i] = info;
2149			break;
2150		}
2151	}
2152	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2153	if (i == COMEDI_NUM_BOARD_MINORS) {
2154		comedi_device_cleanup(info->device);
2155		kfree(info->device);
2156		kfree(info);
2157		rt_printk
2158		    ("comedi: error: ran out of minor numbers for board device files.\n");
2159		return -EBUSY;
2160	}
2161	info->device->minor = i;
2162	csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL,
2163				     MKDEV(COMEDI_MAJOR, i), NULL,
2164				     hardware_device, "comedi%i", i);
2165	if (!IS_ERR(csdev))
2166		info->device->class_dev = csdev;
2167
2168	return i;
2169}
2170
2171void comedi_free_board_minor(unsigned minor)
2172{
2173	unsigned long flags;
2174	struct comedi_device_file_info *info;
2175
2176	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2177	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2178	info = comedi_file_info_table[minor];
2179	comedi_file_info_table[minor] = NULL;
2180	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2181
2182	if (info) {
2183		struct comedi_device *dev = info->device;
2184		if (dev) {
2185			if (dev->class_dev) {
2186				device_destroy(comedi_class,
2187					       MKDEV(COMEDI_MAJOR, dev->minor));
2188			}
2189			comedi_device_cleanup(dev);
2190			kfree(dev);
2191		}
2192		kfree(info);
2193	}
2194}
2195
2196int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s)
2197{
2198	unsigned long flags;
2199	struct comedi_device_file_info *info;
2200	struct device *csdev;
2201	unsigned i;
2202
2203	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2204	if (info == NULL)
2205		return -ENOMEM;
2206	info->device = dev;
2207	info->read_subdevice = s;
2208	info->write_subdevice = s;
2209	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2210	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2211		if (comedi_file_info_table[i] == NULL) {
2212			comedi_file_info_table[i] = info;
2213			break;
2214		}
2215	}
2216	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2217	if (i == COMEDI_NUM_MINORS) {
2218		kfree(info);
2219		rt_printk
2220		    ("comedi: error: ran out of minor numbers for board device files.\n");
2221		return -EBUSY;
2222	}
2223	s->minor = i;
2224	csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev,
2225				     MKDEV(COMEDI_MAJOR, i), NULL, NULL,
2226				     "comedi%i_subd%i", dev->minor,
2227				     (int)(s - dev->subdevices));
2228	if (!IS_ERR(csdev))
2229		s->class_dev = csdev;
2230
2231	return i;
2232}
2233
2234void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2235{
2236	unsigned long flags;
2237	struct comedi_device_file_info *info;
2238
2239	if (s == NULL)
2240		return;
2241	if (s->minor < 0)
2242		return;
2243
2244	BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2245	BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
2246
2247	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2248	info = comedi_file_info_table[s->minor];
2249	comedi_file_info_table[s->minor] = NULL;
2250	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2251
2252	if (s->class_dev) {
2253		device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2254		s->class_dev = NULL;
2255	}
2256	kfree(info);
2257}
2258
2259struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2260{
2261	unsigned long flags;
2262	struct comedi_device_file_info *info;
2263
2264	BUG_ON(minor >= COMEDI_NUM_MINORS);
2265	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
2266	info = comedi_file_info_table[minor];
2267	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
2268	return info;
2269}
2270