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